Compact Byte Code parser and executor for Jerry.

JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Tamas Gergely tgergely.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Zsolt Borbély zsborbely.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Roland Takacs rtakacs.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: István Kádár ikadar@inf.u-szeged.hu
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2016-02-05 00:10:10 -08:00
parent db6caf3c48
commit 4d2dd22ced
92 changed files with 17184 additions and 20276 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2015 Samsung Electronics Co., Ltd.
# Copyright 2015-2016 Samsung Electronics Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -276,7 +276,7 @@ project (Jerry CXX C ASM)
endmacro()
add_jerry_compile_warnings(all extra format-nonliteral init-self conversion sign-conversion format-security missing-declarations)
add_jerry_compile_flags(-pedantic -Wno-stack-protector -Wno-attributes -Wfatal-errors)
add_jerry_compile_flags(-pedantic -Wno-stack-protector -Wno-attributes)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
add_jerry_compile_warnings(logical-op)
else()
+3 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2015 Samsung Electronics Co., Ltd.
# Copyright 2015-2016 Samsung Electronics Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,7 +31,8 @@ project (JerryCore CXX C ASM)
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(DEFINES_JERRY
JERRY_ENABLE_SNAPSHOT
JERRY_ENABLE_SNAPSHOT_SAVE
JERRY_ENABLE_SNAPSHOT_EXEC
JERRY_BUILD_DATE="${JERRY_BUILD_DATE}"
JERRY_COMMIT_HASH="${JERRY_GIT_COMMIT}"
JERRY_BRANCH_NAME="${JERRY_GIT_BRANCH}")
+2 -22
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "jrt-bit-fields.h"
#include "vm-defines.h"
#include "vm-stack.h"
#define JERRY_INTERNAL
@@ -335,13 +336,11 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
JERRY_UNREACHABLE ();
}
case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */
case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */
case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */
case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */
case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */
case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */
case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */
case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */
case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */
case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */
@@ -484,25 +483,6 @@ ecma_gc_run (void)
}
}
/* if some object is referenced from a register variable (i.e. it is root),
* start recursive marking traverse from the object */
for (vm_stack_frame_t *frame_iter_p = vm_stack_get_top_frame ();
frame_iter_p != NULL;
frame_iter_p = frame_iter_p->prev_frame_p)
{
for (uint32_t reg_index = 0; reg_index < frame_iter_p->regs_number; reg_index++)
{
ecma_value_t reg_value = vm_stack_frame_get_reg_value (frame_iter_p, VM_REG_FIRST + reg_index);
if (ecma_is_value_object (reg_value))
{
ecma_object_t *obj_p = ecma_get_object_from_value (reg_value);
ecma_gc_set_object_visited (obj_p, true);
}
}
}
bool marked_anything_during_current_iteration = false;
do
+20 -15
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,6 +82,7 @@ typedef enum
but are stored directly in the array's property list
(used for array elements with non-default attribute values) */
ECMA_SIMPLE_VALUE_ARRAY_HOLE, /**< array hole, used for initialization of an array literal */
ECMA_SIMPLE_VALUE_REGISTER_REF, /**< register reference, a special "base" value for vm */
ECMA_SIMPLE_VALUE__COUNT /** count of simple ecma-values */
} ecma_simple_value_t;
@@ -170,21 +171,12 @@ typedef uint32_t ecma_completion_value_t;
#define ECMA_COMPLETION_VALUE_VALUE_POS (0)
#define ECMA_COMPLETION_VALUE_VALUE_WIDTH (ECMA_VALUE_SIZE)
/**
* Break / continue jump target
*/
#define ECMA_COMPLETION_VALUE_TARGET_POS (0)
#define ECMA_COMPLETION_VALUE_TARGET_WIDTH ((uint32_t) sizeof (vm_instr_counter_t) * JERRY_BITSINBYTE)
/**
* Type (ecma_completion_type_t)
*/
#define ECMA_COMPLETION_VALUE_TYPE_POS (JERRY_MAX (JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_VALUE_POS + \
#define ECMA_COMPLETION_VALUE_TYPE_POS (JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_VALUE_POS + \
ECMA_COMPLETION_VALUE_VALUE_WIDTH, \
JERRY_BITSINBYTE), \
JERRY_ALIGNUP (ECMA_COMPLETION_VALUE_TARGET_POS + \
ECMA_COMPLETION_VALUE_TARGET_WIDTH, \
JERRY_BITSINBYTE)))
JERRY_BITSINBYTE))
#define ECMA_COMPLETION_VALUE_TYPE_WIDTH (8)
/**
@@ -218,12 +210,9 @@ typedef enum
ECMA_INTERNAL_PROPERTY_SCOPE, /**< [[Scope]] */
ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP, /**< [[ParametersMap]] */
ECMA_INTERNAL_PROPERTY_CODE_BYTECODE, /**< first part of [[Code]] - compressed pointer to bytecode array */
ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET, /**< second part of [[Code]] - offset in bytecode array and code flags
* (see also: ecma_pack_code_internal_property_value) */
ECMA_INTERNAL_PROPERTY_NATIVE_CODE, /**< native handler location descriptor */
ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, /**< native handle associated with an object */
ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, /**< object's native free callback */
ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS, /**< [[FormalParameters]] */
ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE, /**< [[Primitive value]] for String objects */
ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE, /**< [[Primitive value]] for Number objects */
ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE, /**< [[Primitive value]] for Boolean objects */
@@ -837,6 +826,22 @@ typedef struct ecma_string_t
*/
typedef uintptr_t ecma_external_pointer_t;
/**
* Compiled byte code data.
*/
typedef struct
{
uint16_t status_flags; /**< various status flags */
} ecma_compiled_code_t;
/**
* Shift value for byte code reference counting.
* The last 10 bit of the first uint16_t value
* of compact byte code or regexp byte code
* is reserved for reference counting.
*/
#define ECMA_BYTECODE_REF_SHIFT 6
/**
* @}
*/
+3 -3
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
* @{
*/
#include "bytecode-data.h"
#include "ecma-alloc.h"
#include "ecma-gc.h"
#include "ecma-globals.h"
@@ -29,9 +28,10 @@
#include "jrt.h"
#include "jrt-libc-includes.h"
#include "lit-char-helpers.h"
#include "lit-literal.h"
#include "lit-magic-strings.h"
#include "vm.h"
#include "rcs-records.h"
#include "vm.h"
/**
* Maximum length of strings' concatenation
+3 -63
View File
@@ -1,4 +1,4 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,16 +26,16 @@
#include "ecma-helpers.h"
#include "jrt.h"
#include "jrt-bit-fields.h"
#include "vm-defines.h"
JERRY_STATIC_ASSERT (sizeof (ecma_value_t) * JERRY_BITSINBYTE >= ECMA_VALUE_SIZE);
JERRY_STATIC_ASSERT (sizeof (ecma_completion_value_t) * JERRY_BITSINBYTE >= ECMA_COMPLETION_VALUE_SIZE);
/**
* Get type field of ecma-value
*
* @return type field
*/
static ecma_type_t __attr_pure___
ecma_type_t __attr_pure___
ecma_get_value_type_field (ecma_value_t value) /**< ecma-value */
{
return (ecma_type_t) jrt_extract_bit_field (value,
@@ -474,19 +474,6 @@ ecma_get_completion_value_value_field (ecma_completion_value_t completion_value)
ECMA_COMPLETION_VALUE_VALUE_WIDTH);
} /* ecma_get_completion_value_value_field */
/**
* Get target of break / continue completion value
*
* @return instruction counter
*/
static vm_instr_counter_t
ecma_get_completion_value_target (ecma_completion_value_t completion_value) /**< completion value */
{
return (vm_instr_counter_t) jrt_extract_bit_field (completion_value,
ECMA_COMPLETION_VALUE_TARGET_POS,
ECMA_COMPLETION_VALUE_TARGET_WIDTH);
} /* ecma_get_completion_value_target */
/**
* Set type field of completion value
*
@@ -519,21 +506,6 @@ ecma_set_completion_value_value_field (ecma_completion_value_t completion_value,
ECMA_COMPLETION_VALUE_VALUE_WIDTH);
} /* ecma_set_completion_value_value_field */
/**
* Set target of break / continue completion value
*
* @return completion value with updated field
*/
static ecma_completion_value_t __attr_const___
ecma_set_completion_value_target (ecma_completion_value_t completion_value, /**< completion value
* to set field in */
vm_instr_counter_t target) /**< break / continue target */
{
return (ecma_completion_value_t) jrt_set_bit_field_value (completion_value,
target,
ECMA_COMPLETION_VALUE_TARGET_POS,
ECMA_COMPLETION_VALUE_TARGET_WIDTH);
} /* ecma_set_completion_value_target */
/**
* Normal, throw, return, exit and meta completion values constructor
@@ -652,24 +624,6 @@ ecma_make_meta_completion_value (void)
ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY));
} /* ecma_make_meta_completion_value */
/**
* Break / continue completion values constructor
*
* @return completion value
*/
ecma_completion_value_t __attr_const___
ecma_make_jump_completion_value (vm_instr_counter_t target) /**< target break / continue */
{
ecma_completion_value_t completion_value = 0;
completion_value = ecma_set_completion_value_type_field (completion_value,
ECMA_COMPLETION_TYPE_JUMP);
completion_value = ecma_set_completion_value_target (completion_value,
target);
return completion_value;
} /* ecma_make_jump_completion_value */
/**
* Get ecma-value from specified completion value
*
@@ -722,20 +676,6 @@ ecma_get_object_from_completion_value (ecma_completion_value_t completion_value)
return ecma_get_object_from_value (ecma_get_completion_value_value (completion_value));
} /* ecma_get_object_from_completion_value */
/**
* Get break / continue target from completion value
*
* @return instruction counter
*/
vm_instr_counter_t
ecma_get_jump_target_from_completion_value (ecma_completion_value_t completion_value) /**< completion
* value */
{
JERRY_ASSERT (ecma_get_completion_value_type_field (completion_value) == ECMA_COMPLETION_TYPE_JUMP);
return ecma_get_completion_value_target (completion_value);
} /* ecma_get_jump_target_from_completion_value */
/**
* Copy ecma-completion value.
*
+102 -19
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +27,8 @@
#include "ecma-helpers.h"
#include "ecma-lcache.h"
#include "jrt-bit-fields.h"
#include "byte-code.h"
#include "re-compiler.h"
/**
* Create an object with specified prototype object
@@ -763,17 +766,6 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
break;
}
case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a strings' collection */
{
if (property_value != ECMA_NULL_POINTER)
{
ecma_free_values_collection (ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t,
property_value),
false);
}
break;
}
case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */
{
ecma_string_t *str_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t,
@@ -807,8 +799,6 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t */
case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t */
case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */
case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */
case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */
case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */
case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */
case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */
@@ -840,15 +830,24 @@ ecma_free_internal_property (ecma_property_t *property_p) /**< the property */
* but number of the real internal property types */
{
JERRY_UNREACHABLE ();
break;
}
case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE:
{
void *bytecode_p = ECMA_GET_POINTER (void, property_value);
if (bytecode_p)
case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */
{
ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, property_value));
break;
}
case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: /* compressed pointer to a regexp bytecode array */
{
ecma_compiled_code_t *bytecode_p = ECMA_GET_POINTER (ecma_compiled_code_t, property_value);
if (bytecode_p != NULL)
{
mem_heap_free_block (bytecode_p);
ecma_bytecode_deref (bytecode_p);
}
break;
}
}
@@ -1328,6 +1327,90 @@ ecma_get_property_descriptor_from_property (ecma_property_t *prop_p) /**< proper
return prop_desc;
} /* ecma_get_property_descriptor_from_property */
/**
* Increase reference counter of Compact
* Byte Code or regexp byte code.
*/
void
ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
{
/* Abort program if maximum reference number is reached.
* Note: This is not tested for objects. */
if ((bytecode_p->status_flags >> ECMA_BYTECODE_REF_SHIFT) >= 0x3ff)
{
jerry_fatal (ERR_UNIMPLEMENTED_CASE);
}
bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags + (1 << ECMA_BYTECODE_REF_SHIFT));
} /* ecma_bytecode_ref */
/**
* Decrease reference counter of Compact
* Byte Code or regexp byte code.
*/
void
ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
{
JERRY_ASSERT ((bytecode_p->status_flags >> ECMA_BYTECODE_REF_SHIFT) > 0);
bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags - (1 << ECMA_BYTECODE_REF_SHIFT));
if (bytecode_p->status_flags >= (1 << ECMA_BYTECODE_REF_SHIFT))
{
/* Non-zero reference counter. */
return;
}
if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
{
lit_cpointer_t *literal_start_p = NULL;
uint32_t literal_end;
uint32_t const_literal_end;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
literal_start_p = (lit_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t));
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
}
else
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
literal_start_p = (lit_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t));
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
}
for (uint32_t i = const_literal_end; i < literal_end; i++)
{
mem_cpointer_t bytecode_cpointer = literal_start_p[i].value.base_cp;
ecma_compiled_code_t *bytecode_literal_p = ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t,
bytecode_cpointer);
/* Self references are ignored. */
if (bytecode_literal_p != bytecode_p)
{
ecma_bytecode_deref (bytecode_literal_p);
}
}
}
else
{
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
re_compiled_code_t *re_bytecode_p = (re_compiled_code_t *) bytecode_p;
ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, re_bytecode_p->pattern_cp));
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
}
mem_heap_free_block (bytecode_p);
} /* ecma_bytecode_deref */
/**
* @}
* @}
+7 -5
View File
@@ -1,5 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
#include "ecma-globals.h"
#include "lit-strings.h"
#include "mem-allocator.h"
#include "opcodes.h"
/**
* Get value of pointer from specified non-null compressed pointer.
@@ -53,6 +52,8 @@
#define ECMA_SET_POINTER(field, non_compressed_pointer) MEM_CP_SET_POINTER (field, non_compressed_pointer)
/* ecma-helpers-value.cpp */
extern ecma_type_t ecma_get_value_type_field (ecma_value_t) __attr_pure___;
extern bool ecma_is_value_empty (ecma_value_t);
extern bool ecma_is_value_undefined (ecma_value_t);
extern bool ecma_is_value_null (ecma_value_t);
@@ -84,12 +85,10 @@ extern ecma_completion_value_t ecma_make_throw_obj_completion_value (ecma_object
extern ecma_completion_value_t ecma_make_empty_completion_value (void);
extern ecma_completion_value_t ecma_make_return_completion_value (ecma_value_t);
extern ecma_completion_value_t ecma_make_meta_completion_value (void);
extern ecma_completion_value_t ecma_make_jump_completion_value (vm_instr_counter_t);
extern ecma_value_t ecma_get_completion_value_value (ecma_completion_value_t);
extern ecma_number_t *ecma_get_number_from_completion_value (ecma_completion_value_t) __attr_const___;
extern ecma_string_t *ecma_get_string_from_completion_value (ecma_completion_value_t) __attr_const___;
extern ecma_object_t *ecma_get_object_from_completion_value (ecma_completion_value_t) __attr_const___;
extern vm_instr_counter_t ecma_get_jump_target_from_completion_value (ecma_completion_value_t);
extern ecma_completion_value_t ecma_copy_completion_value (ecma_completion_value_t);
extern void ecma_free_completion_value (ecma_completion_value_t);
@@ -254,6 +253,9 @@ extern ecma_property_descriptor_t ecma_make_empty_property_descriptor (void);
extern void ecma_free_property_descriptor (ecma_property_descriptor_t *);
extern ecma_property_descriptor_t ecma_get_property_descriptor_from_property (ecma_property_t *);
extern void ecma_bytecode_ref (ecma_compiled_code_t *);
extern void ecma_bytecode_deref (ecma_compiled_code_t *);
/* ecma-helpers-external-pointers.cpp */
extern bool
ecma_create_external_pointer_property (ecma_object_t *, ecma_internal_property_id_t, ecma_external_pointer_t);
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,8 +50,8 @@ ecma_finalize (void)
mem_unregister_a_try_give_memory_back_callback (ecma_try_to_give_back_some_memory);
ecma_finalize_environment ();
ecma_finalize_builtins ();
ecma_lcache_invalidate_all ();
ecma_finalize_builtins ();
ecma_gc_run ();
} /* ecma_finalize */
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument
else
{
ecma_string_t *pattern_string_p = NULL;
uint8_t flags = 0;
uint16_t flags = 0;
if (ecma_is_value_object (pattern_arg)
&& ecma_object_get_class_name (ecma_get_object_from_value (pattern_arg)) == LIT_MAGIC_STRING_REGEXP_UL)
@@ -125,17 +125,20 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument
ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
FIXME ("We currently have to re-compile the bytecode, because we can't copy it without knowing its length.")
re_bytecode_t *new_bc_p = NULL;
/* FIXME: "We currently have to re-compile the bytecode, because
* we can't copy it without knowing its length."
*/
re_compiled_code_t *new_bc_p = NULL;
ecma_completion_value_t bc_comp = re_compile_bytecode (&new_bc_p, pattern_string_p, flags);
/* Should always succeed, since we're compiling from a source that has been compiled previously. */
JERRY_ASSERT (ecma_is_completion_value_empty (bc_comp));
re_bytecode_t *old_bc_p = ECMA_GET_POINTER (re_bytecode_t,
bc_prop_p->u.internal_property.value);
re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t,
bc_prop_p->u.internal_property.value);
if (old_bc_p != NULL)
{
mem_heap_free_block (old_bc_p);
/* Free the old bytecode */
ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
}
ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);
@@ -189,17 +192,18 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument
ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
/* Try to compile bytecode from new source. */
re_bytecode_t *new_bc_p = NULL;
ECMA_TRY_CATCH (bc_dummy, re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value);
re_compiled_code_t *new_bc_p = NULL;
ECMA_TRY_CATCH (bc_dummy,
re_compile_bytecode (&new_bc_p, pattern_string_p, flags),
ret_value);
re_bytecode_t *old_bc_p = ECMA_GET_POINTER (re_bytecode_t,
bc_prop_p->u.internal_property.value);
re_compiled_code_t *old_bc_p = ECMA_GET_POINTER (re_compiled_code_t,
bc_prop_p->u.internal_property.value);
if (old_bc_p != NULL)
{
/* Replace old bytecode with new one. */
mem_heap_free_block (old_bc_p);
/* Free the old bytecode */
ecma_bytecode_deref ((ecma_compiled_code_t *) old_bc_p);
}
ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -271,7 +271,6 @@ ecma_finalize_builtins (void)
if (ecma_builtin_objects[id] != NULL)
{
ecma_deref_object (ecma_builtin_objects[id]);
ecma_builtin_objects[id] = NULL;
}
}
+3 -11
View File
@@ -1,4 +1,4 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* limitations under the License.
*/
#include "bytecode-data.h"
#include "ecma-builtins.h"
#include "ecma-exceptions.h"
#include "ecma-eval.h"
@@ -93,17 +92,15 @@ ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters
ecma_completion_value_t completion;
const bytecode_data_header_t *bytecode_data_p;
ecma_compiled_code_t *bytecode_data_p;
jsp_status_t parse_status;
bool is_strict_call = (is_direct && is_called_from_strict_mode_code);
bool code_contains_functions;
parse_status = parser_parse_eval (code_p,
code_buffer_size,
is_strict_call,
&bytecode_data_p,
&code_contains_functions);
&bytecode_data_p);
if (parse_status == JSP_STATUS_SYNTAX_ERROR)
{
@@ -118,11 +115,6 @@ ecma_op_eval_chars_buffer (const jerry_api_char_t *code_p, /**< code characters
JERRY_ASSERT (parse_status == JSP_STATUS_OK);
completion = vm_run_eval (bytecode_data_p, is_direct);
if (!code_contains_functions)
{
bc_remove_bytecode_data (bytecode_data_p);
}
}
return completion;
+6 -6
View File
@@ -35,13 +35,13 @@
*/
typedef enum
{
ECMA_ERROR_COMMON, /**< Error */
ECMA_ERROR_EVAL, /**< EvalError */
ECMA_ERROR_RANGE, /**< RangeError */
ECMA_ERROR_COMMON, /**< Error */
ECMA_ERROR_EVAL, /**< EvalError */
ECMA_ERROR_RANGE, /**< RangeError */
ECMA_ERROR_REFERENCE, /**< ReferenceError */
ECMA_ERROR_SYNTAX, /**< SyntaxError */
ECMA_ERROR_TYPE, /**< TypeError */
ECMA_ERROR_URI /**< URIError */
ECMA_ERROR_SYNTAX, /**< SyntaxError */
ECMA_ERROR_TYPE, /**< TypeError */
ECMA_ERROR_URI /**< URIError */
} ecma_standard_error_t;
extern ecma_object_t *ecma_new_standard_error (ecma_standard_error_t);
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +14,6 @@
* limitations under the License.
*/
#include "bytecode-data.h"
#include "ecma-alloc.h"
#include "ecma-builtin-helpers.h"
#include "ecma-builtins.h"
@@ -37,93 +37,6 @@
* @{
*/
/**
* Pack 'is_strict', 'do_instantiate_arguments_object' flags and instruction position to value
* that can be stored in an [[Code]] internal property.
*
* @return packed value
*/
static uint32_t
ecma_pack_code_internal_property_value (bool is_strict, /**< is code strict? */
bool do_instantiate_args_obj, /**< should an Arguments object be
* instantiated for the code */
bool is_arguments_moved_to_regs, /**< values of the function's arguments
* are placed on registers */
bool is_no_lex_env, /**< the function needs no lexical environment */
vm_instr_counter_t instr_oc) /**< position of first instruction */
{
uint32_t value = instr_oc;
const uint32_t is_strict_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 1);
const uint32_t do_instantiate_arguments_object_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 2);
const uint32_t arguments_moved_to_regs_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 3);
const uint32_t no_lex_env_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 4);
JERRY_ASSERT (((value) & (1u << is_strict_bit_offset)) == 0);
JERRY_ASSERT (((value) & (1u << do_instantiate_arguments_object_bit_offset)) == 0);
JERRY_ASSERT (((value) & (1u << arguments_moved_to_regs_bit_offset)) == 0);
JERRY_ASSERT (((value) & (1u << no_lex_env_bit_offset)) == 0);
if (is_strict)
{
value |= (1u << is_strict_bit_offset);
}
if (do_instantiate_args_obj)
{
value |= (1u << do_instantiate_arguments_object_bit_offset);
}
if (is_arguments_moved_to_regs)
{
value |= (1u << arguments_moved_to_regs_bit_offset);
}
if (is_no_lex_env)
{
value |= (1u << no_lex_env_bit_offset);
}
return value;
} /* ecma_pack_code_internal_property_value */
/**
* Unpack 'is_strict', 'do_instantiate_arguments_object' flags and instruction position from value
* that can be stored in an [[Code]] internal property.
*
* @return instruction position
*/
static vm_instr_counter_t
ecma_unpack_code_internal_property_value (uint32_t value, /**< packed value */
bool* out_is_strict_p, /**< out: is code strict? */
bool* out_do_instantiate_args_obj_p, /**< should an Arguments object be
* instantiated for the code */
bool* out_is_arguments_moved_to_regs_p, /**< values of the function's
* arguments are placed
* on registers */
bool* out_is_no_lex_env_p) /**< the function needs no lexical environment */
{
JERRY_ASSERT (out_is_strict_p != NULL);
JERRY_ASSERT (out_do_instantiate_args_obj_p != NULL);
JERRY_ASSERT (out_is_arguments_moved_to_regs_p != NULL);
JERRY_ASSERT (out_is_no_lex_env_p != NULL);
const uint32_t is_strict_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 1);
const uint32_t do_instantiate_arguments_object_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 2);
const uint32_t is_arguments_moved_to_regs_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 3);
const uint32_t is_no_lex_env_bit_offset = (uint32_t) (sizeof (value) * JERRY_BITSINBYTE - 4);
*out_is_strict_p = ((value & (1u << is_strict_bit_offset)) != 0);
*out_do_instantiate_args_obj_p = ((value & (1u << do_instantiate_arguments_object_bit_offset)) != 0);
*out_is_arguments_moved_to_regs_p = ((value & (1u << is_arguments_moved_to_regs_bit_offset)) != 0);
*out_is_no_lex_env_p = ((value & (1u << is_no_lex_env_bit_offset)) != 0);
value &= ~((1u << is_strict_bit_offset)
| (1u << do_instantiate_arguments_object_bit_offset)
| (1u << is_arguments_moved_to_regs_bit_offset)
| (1u << is_no_lex_env_bit_offset));
return (vm_instr_counter_t) value;
} /* ecma_unpack_code_internal_property_value */
/**
* IsCallable operation.
*
@@ -238,49 +151,17 @@ ecma_function_bind_merge_arg_lists (ecma_object_t *func_obj_p, /**< Function obj
* @return pointer to newly created Function object
*/
ecma_object_t*
ecma_op_create_function_object (ecma_collection_header_t *formal_params_collection_p, /**< formal parameters collection
* Warning:
* the collection should not
* be changed / used / freed
* by caller after passing it
* to the routine */
ecma_object_t *scope_p, /**< function's scope */
ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */
bool is_decl_in_strict_mode, /**< is function declared in strict mode code? */
const bytecode_data_header_t *bytecode_header_p, /**< byte-code */
vm_instr_counter_t first_instr_pos) /**< position of first instruction
* of function's body */
const ecma_compiled_code_t *bytecode_data_p) /**< byte-code array */
{
bool is_strict_mode_code = is_decl_in_strict_mode;
bool do_instantiate_arguments_object = true;
bool is_arguments_moved_to_regs = false;
bool is_no_lex_env = false;
vm_instr_counter_t instr_pos = first_instr_pos;
if (bytecode_header_p->is_strict)
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)
{
is_strict_mode_code = true;
}
if (!bytecode_header_p->is_ref_arguments_identifier
&& !bytecode_header_p->is_ref_eval_identifier)
{
/* the code doesn't use 'arguments' identifier
* and doesn't perform direct call to eval,
* so Arguments object can't be referenced */
do_instantiate_arguments_object = false;
}
if (bytecode_header_p->is_args_moved_to_regs)
{
is_arguments_moved_to_regs = true;
}
if (bytecode_header_p->is_no_lex_env)
{
is_no_lex_env = true;
}
// 1., 4., 13.
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE);
@@ -306,25 +187,12 @@ ecma_op_create_function_object (ecma_collection_header_t *formal_params_collecti
ecma_property_t *scope_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_SCOPE);
ECMA_SET_POINTER (scope_prop_p->u.internal_property.value, scope_p);
// 10., 11.
if (formal_params_collection_p != NULL
&& formal_params_collection_p->unit_number != 0)
{
ecma_property_t *formal_params_prop_p = ecma_create_internal_property (f,
ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS);
ECMA_SET_POINTER (formal_params_prop_p->u.internal_property.value, formal_params_collection_p);
}
// 10.
// 11.
// 12.
ecma_property_t *bytecode_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
MEM_CP_SET_NON_NULL_POINTER (bytecode_prop_p->u.internal_property.value, bytecode_header_p);
ecma_property_t *code_prop_p = ecma_create_internal_property (f, ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET);
code_prop_p->u.internal_property.value = ecma_pack_code_internal_property_value (is_strict_mode_code,
do_instantiate_arguments_object,
is_arguments_moved_to_regs,
is_no_lex_env,
instr_pos);
MEM_CP_SET_NON_NULL_POINTER (bytecode_prop_p->u.internal_property.value, bytecode_data_p);
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p);
// 14.
// 15.
@@ -446,37 +314,20 @@ ecma_op_function_try_lazy_instantiate_property (ecma_object_t *obj_p, /**< the f
// 14
ecma_number_t *len_p = ecma_alloc_number ();
ecma_property_t *formal_parameters_prop_p = ecma_find_internal_property (obj_p,
ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS);
if (formal_parameters_prop_p == NULL)
ecma_property_t *bytecode_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = MEM_CP_GET_POINTER (const ecma_compiled_code_t, bytecode_prop_p->u.internal_property.value);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
ecma_property_t *bytecode_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
ecma_property_t *code_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET);
uint32_t code_prop_value = code_prop_p->u.internal_property.value;
bool is_strict;
bool do_instantiate_args_obj;
bool is_arguments_moved_to_regs;
bool is_no_lex_env;
const bytecode_data_header_t *bytecode_header_p;
bytecode_header_p = MEM_CP_GET_POINTER (const bytecode_data_header_t, bytecode_prop_p->u.internal_property.value);
vm_instr_counter_t code_first_instr_pos = ecma_unpack_code_internal_property_value (code_prop_value,
&is_strict,
&do_instantiate_args_obj,
&is_arguments_moved_to_regs,
&is_no_lex_env);
*len_p = vm_get_scope_args_num (bytecode_header_p, code_first_instr_pos);
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
*len_p = args_p->argument_end;
}
else
{
ecma_collection_header_t *formal_parameters_p;
formal_parameters_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t,
formal_parameters_prop_p->u.internal_property.value);
*len_p = ecma_uint32_to_number (formal_parameters_p->unit_number);
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p;
*len_p = args_p->argument_end;
}
// 15
@@ -619,154 +470,6 @@ ecma_op_create_external_function_object (ecma_external_pointer_t code_p) /**< po
return function_obj_p;
} /* ecma_op_create_external_function_object */
/**
* Setup variables for arguments listed in formal parameter list,
* and, if necessary, Arguments object with 'arguments' binding.
*
* See also:
* Declaration binding instantiation (ECMA-262 v5, 10.5), block 4 and 7
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
ecma_function_call_setup_args_variables (ecma_object_t *func_obj_p, /**< Function object */
ecma_object_t *env_p, /**< lexical environment */
ecma_collection_header_t *arg_collection_p, /**< arguments collection */
bool is_strict, /**< flag indicating strict mode */
bool do_instantiate_arguments_object) /**< flag indicating whether
* Arguments object should be
* instantiated */
{
ecma_collection_header_t *formal_parameters_p = NULL;
ecma_property_t *formal_parameters_prop_p = ecma_find_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS);
if (formal_parameters_prop_p != NULL)
{
formal_parameters_p = ECMA_GET_POINTER (ecma_collection_header_t,
formal_parameters_prop_p->u.internal_property.value);
ecma_length_t formal_parameters_count = formal_parameters_p->unit_number;
ecma_collection_iterator_t arguments_iterator, formal_params_iterator;
ecma_collection_iterator_init (&arguments_iterator, arg_collection_p);
ecma_collection_iterator_init (&formal_params_iterator, formal_parameters_p);
/*
* Formal parameter list is stored in reversed order
*
* Although, specification defines ascending order of formal parameters list enumeration,
* implementation enumerates the parameters in descending order.
*
* In the case, redundant SetMutableBinding invocation could be avoided.
*/
for (ecma_length_t n = 0;
n < formal_parameters_count;
n++)
{
ecma_value_t arg_value;
if (ecma_collection_iterator_next (&arguments_iterator))
{
arg_value = *arguments_iterator.current_value_p;
}
else
{
arg_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
bool is_moved = ecma_collection_iterator_next (&formal_params_iterator);
JERRY_ASSERT (is_moved);
ecma_value_t formal_parameter_name_value = *formal_params_iterator.current_value_p;
ecma_string_t *formal_parameter_name_string_p = ecma_get_string_from_value (formal_parameter_name_value);
bool arg_already_declared = ecma_op_has_binding (env_p, formal_parameter_name_string_p);
if (!arg_already_declared)
{
ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p,
formal_parameter_name_string_p,
false);
if (ecma_is_completion_value_throw (completion))
{
return completion;
}
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
}
ecma_completion_value_t completion = ecma_op_set_mutable_binding (env_p,
formal_parameter_name_string_p,
arg_value,
is_strict);
if (ecma_is_completion_value_throw (completion))
{
return completion;
}
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
}
}
if (do_instantiate_arguments_object)
{
/*
* According to ECMA-262 v5, 10.5, the Arguments object should be instantiated
* after instantiating declared functions, and only if there is no binding named 'arguments'
* by that time.
*
* However, we can setup Arguments object and 'arguments' binding here, because:
* - instantiation of Arguments object itself doesn't have any side effects;
* - if 'arguments' is name of a declared function in current scope,
* value of the binding would be overwritten, execution would proceed in correct state.
* - declaration of function, named 'arguments', is considered to be unrecommended (and so, rare) case,
* so instantiation of Arguments object here, in general, is supposed to not affect resource consumption
* significantly.
*/
ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
bool binding_already_declared = ecma_op_has_binding (env_p, arguments_string_p);
if (!binding_already_declared)
{
ecma_object_t *args_obj_p = ecma_op_create_arguments_object (func_obj_p,
env_p,
formal_parameters_p,
arg_collection_p,
is_strict);
if (is_strict)
{
ecma_op_create_immutable_binding (env_p, arguments_string_p);
ecma_op_initialize_immutable_binding (env_p, arguments_string_p, ecma_make_object_value (args_obj_p));
}
else
{
ecma_completion_value_t completion = ecma_op_create_mutable_binding (env_p,
arguments_string_p,
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
completion = ecma_op_set_mutable_binding (env_p,
arguments_string_p,
ecma_make_object_value (args_obj_p),
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
}
ecma_deref_object (args_obj_p);
}
ecma_deref_ecma_string (arguments_string_p);
}
return ecma_make_empty_completion_value ();
} /* ecma_function_call_setup_args_variables */
/**
* [[Call]] implementation for Function objects,
* created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION)
@@ -869,27 +572,116 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object *
ecma_completion_value_t
ecma_op_function_call_array_args (ecma_object_t *func_obj_p, /**< Function object */
ecma_value_t this_arg_value, /**< 'this' argument's value */
const ecma_value_t* arguments_list_p, /**< arguments list */
const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_list_len) /**< length of arguments list */
{
if (arguments_list_len == 0)
{
return ecma_op_function_call (func_obj_p, this_arg_value, NULL);
}
else
if (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION
&& !ecma_get_object_is_builtin (func_obj_p))
{
ecma_collection_header_t *arg_collection_p = ecma_new_values_collection (arguments_list_p,
arguments_list_len,
true);
/* Fast call. */
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ecma_completion_value_t ret_value = ecma_op_function_call (func_obj_p,
this_arg_value,
arg_collection_p);
/* Entering Function Code (ECMA-262 v5, 10.4.3) */
ecma_property_t *scope_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE);
ecma_property_t *bytecode_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
ecma_free_values_collection (arg_collection_p, true);
ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
scope_prop_p->u.internal_property.value);
// 8.
ecma_value_t this_binding;
bool is_strict;
bool is_no_lex_env;
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = MEM_CP_GET_POINTER (const ecma_compiled_code_t,
bytecode_prop_p->u.internal_property.value);
is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false;
is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false;
// 1.
if (is_strict)
{
this_binding = ecma_copy_value (this_arg_value, true);
}
else if (ecma_is_value_undefined (this_arg_value)
|| ecma_is_value_null (this_arg_value))
{
// 2.
this_binding = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL));
}
else
{
// 3., 4.
ecma_completion_value_t completion = ecma_op_to_object (this_arg_value);
JERRY_ASSERT (ecma_is_completion_value_normal (completion));
this_binding = ecma_get_completion_value_value (completion);
}
// 5.
ecma_object_t *local_env_p;
if (is_no_lex_env)
{
local_env_p = scope_p;
}
else
{
local_env_p = ecma_create_decl_lex_env (scope_p);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED)
{
ecma_op_create_arguments_object_array_args (func_obj_p,
local_env_p,
arguments_list_p,
arguments_list_len,
bytecode_data_p);
}
}
ecma_completion_value_t completion = vm_run_array_args (bytecode_data_p,
this_binding,
local_env_p,
false,
arguments_list_p,
arguments_list_len);
if (ecma_is_completion_value_return (completion))
{
ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion));
}
else
{
ret_value = completion;
}
if (!is_no_lex_env)
{
ecma_deref_object (local_env_p);
}
ecma_free_value (this_binding, true);
return ret_value;
}
/* Slow call. */
ecma_collection_header_t *arg_collection_p = ecma_new_values_collection (arguments_list_p,
arguments_list_len,
true);
ecma_completion_value_t ret_value = ecma_op_function_call (func_obj_p,
this_arg_value,
arg_collection_p);
ecma_free_values_collection (arg_collection_p, true);
return ret_value;
} /* ecma_op_function_call_array_args */
/**
@@ -926,29 +718,21 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
/* Entering Function Code (ECMA-262 v5, 10.4.3) */
ecma_property_t *scope_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_SCOPE);
ecma_property_t *bytecode_prop_p = ecma_get_internal_property (func_obj_p, ECMA_INTERNAL_PROPERTY_CODE_BYTECODE);
ecma_property_t *code_prop_p = ecma_get_internal_property (func_obj_p,
ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET);
ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t,
scope_prop_p->u.internal_property.value);
uint32_t code_prop_value = code_prop_p->u.internal_property.value;
// 8.
ecma_value_t this_binding;
bool is_strict;
bool do_instantiate_args_obj;
bool is_arguments_moved_to_regs;
bool is_no_lex_env;
const bytecode_data_header_t *bytecode_data_p;
bytecode_data_p = MEM_CP_GET_POINTER (const bytecode_data_header_t, bytecode_prop_p->u.internal_property.value);
const ecma_compiled_code_t *bytecode_data_p;
bytecode_data_p = MEM_CP_GET_POINTER (const ecma_compiled_code_t, bytecode_prop_p->u.internal_property.value);
vm_instr_counter_t code_first_instr_pos = ecma_unpack_code_internal_property_value (code_prop_value,
&is_strict,
&do_instantiate_args_obj,
&is_arguments_moved_to_regs,
&is_no_lex_env);
is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false;
is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false;
ecma_value_t this_binding;
// 1.
if (is_strict)
{
@@ -978,63 +762,32 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */
else
{
local_env_p = ecma_create_decl_lex_env (scope_p);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED)
{
ecma_op_create_arguments_object (func_obj_p,
local_env_p,
arg_collection_p,
bytecode_data_p);
}
}
if (is_arguments_moved_to_regs)
{
ecma_completion_value_t completion = vm_run_from_pos (bytecode_data_p,
code_first_instr_pos,
this_binding,
local_env_p,
is_strict,
false,
arg_collection_p);
ecma_completion_value_t completion = vm_run (bytecode_data_p,
this_binding,
local_env_p,
false,
arg_collection_p);
if (ecma_is_completion_value_return (completion))
{
ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion));
}
else
{
ret_value = completion;
}
if (ecma_is_completion_value_return (completion))
{
ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion));
}
else
{
// 9.
ECMA_TRY_CATCH (args_var_declaration_ret,
ecma_function_call_setup_args_variables (func_obj_p,
local_env_p,
arg_collection_p,
is_strict,
do_instantiate_args_obj),
ret_value);
ecma_completion_value_t completion = vm_run_from_pos (bytecode_data_p,
code_first_instr_pos,
this_binding,
local_env_p,
is_strict,
false,
NULL);
if (ecma_is_completion_value_return (completion))
{
ret_value = ecma_make_normal_completion_value (ecma_get_completion_value_value (completion));
}
else
{
ret_value = completion;
}
ECMA_FINALIZE (args_var_declaration_ret);
ret_value = completion;
}
if (is_no_lex_env)
{
/* do nothing */
}
else
if (!is_no_lex_env)
{
ecma_deref_object (local_env_p);
}
@@ -1263,26 +1016,16 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
ecma_completion_value_t
ecma_op_function_declaration (ecma_object_t *lex_env_p, /**< lexical environment */
ecma_string_t *function_name_p, /**< function name */
const bytecode_data_header_t *bytecode_data_p, /**< byte-code data */
vm_instr_counter_t function_first_instr_pos, /**< position of first instruction
* of function code */
ecma_collection_header_t *formal_params_collection_p, /**< formal parameters collection
* Warning:
* the collection should not
* be changed / used / freed
* by caller after passing it
* to the routine */
const ecma_compiled_code_t *bytecode_data_p, /**< bytecode data */
bool is_decl_in_strict_mode, /**< flag, indicating if function is
* declared in strict mode code */
bool is_configurable_bindings) /**< flag indicating whether function
* is declared in eval code */
{
// b.
ecma_object_t *func_obj_p = ecma_op_create_function_object (formal_params_collection_p,
lex_env_p,
ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p,
is_decl_in_strict_mode,
bytecode_data_p,
function_first_instr_pos);
bytecode_data_p);
// c.
bool func_already_declared = ecma_op_has_binding (lex_env_p, function_name_p);
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,8 +30,7 @@ extern bool ecma_op_is_callable (ecma_value_t);
extern bool ecma_is_constructor (ecma_value_t);
extern ecma_object_t *
ecma_op_create_function_object (ecma_collection_header_t *, ecma_object_t *,
bool, const bytecode_data_header_t *, vm_instr_counter_t);
ecma_op_create_function_object (ecma_object_t *, bool, const ecma_compiled_code_t *);
extern void
ecma_op_function_list_lazy_property_names (bool,
@@ -59,8 +58,8 @@ extern ecma_completion_value_t
ecma_op_function_has_instance (ecma_object_t *, ecma_value_t);
extern ecma_completion_value_t
ecma_op_function_declaration (ecma_object_t *, ecma_string_t *, const bytecode_data_header_t *, vm_instr_counter_t,
ecma_collection_header_t *, bool, bool);
ecma_op_function_declaration (ecma_object_t *, ecma_string_t *,
const ecma_compiled_code_t *, bool, bool);
/**
* @}
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,33 +36,24 @@
#include "jrt.h"
/**
* Arguments object creation operation.
* Arguments object creation common part.
*
* See also: ECMA-262 v5, 10.6
*
* @return pointer to newly created Arguments object
*/
ecma_object_t*
ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function */
ecma_object_t *lex_env_p, /**< lexical environment the Arguments
object is created for */
ecma_collection_header_t *formal_params_p, /**< formal parameters collection */
ecma_collection_header_t *arg_collection_p, /**< arguments collection */
bool is_strict) /**< flag indicating whether strict mode is enabled */
static void
ecma_op_create_arguments_object_common (ecma_object_t *obj_p, /**< arguments object */
ecma_object_t *func_obj_p, /**< callee function */
ecma_object_t *lex_env_p, /**< lexical environment the Arguments
object is created for */
ecma_length_t arguments_number, /**< length of arguments list */
const ecma_compiled_code_t *bytecode_data_p) /**< bytecode data */
{
const ecma_length_t arguments_number = arg_collection_p != NULL ? arg_collection_p->unit_number : 0;
bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0;
// 1.
ecma_number_t *len_p = ecma_alloc_number ();
*len_p = ecma_uint32_to_number (arguments_number);
// 2., 3., 6.
ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
ecma_object_t *obj_p = ecma_create_object (prototype_p, true, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (prototype_p);
// 4.
ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS);
class_prop_p->u.internal_property.value = LIT_MAGIC_STRING_ARGUMENTS_UL;
@@ -81,39 +73,29 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function
ecma_dealloc_number (len_p);
// 11.a, 11.b
ecma_collection_iterator_t args_iterator;
ecma_collection_iterator_init (&args_iterator, arg_collection_p);
for (ecma_length_t indx = 0;
indx < arguments_number;
indx++)
{
bool is_moved = ecma_collection_iterator_next (&args_iterator);
JERRY_ASSERT (is_moved);
ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx);
completion = ecma_builtin_helper_def_prop (obj_p,
indx_string_p,
*args_iterator.current_value_p,
true, /* Writable */
true, /* Enumerable */
true, /* Configurable */
false); /* Failure handling */
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
ecma_deref_ecma_string (indx_string_p);
}
ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor ();
if (formal_params_p != NULL)
if (bytecode_data_p != NULL)
{
const ecma_length_t formal_params_number = formal_params_p->unit_number;
ecma_length_t formal_params_number;
lit_cpointer_t *literal_p;
ecma_collection_iterator_t formal_params_iterator;
ecma_collection_iterator_init (&formal_params_iterator, formal_params_p);
if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p;
uint8_t *byte_p = (uint8_t *) bytecode_data_p;
formal_params_number = args_p->argument_end;
literal_p = (lit_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t));
}
else
{
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p;
uint8_t *byte_p = (uint8_t *) bytecode_data_p;
formal_params_number = args_p->argument_end;
literal_p = (lit_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t));
}
if (!is_strict
&& arguments_number > 0
@@ -123,68 +105,35 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function
ecma_object_t *map_p = ecma_op_create_object_object_noarg ();
// 11.c
MEM_DEFINE_LOCAL_ARRAY (formal_params, formal_params_number, ecma_string_t *);
JERRY_ASSERT (formal_params_iterator.current_value_p == NULL);
uint32_t param_index;
for (param_index = 0;
ecma_collection_iterator_next (&formal_params_iterator);
param_index++)
{
JERRY_ASSERT (formal_params_iterator.current_value_p != NULL);
JERRY_ASSERT (param_index < formal_params_number);
JERRY_ASSERT (ecma_is_value_string (*formal_params_iterator.current_value_p));
ecma_string_t *param_name_p = ecma_get_string_from_value (*formal_params_iterator.current_value_p);
formal_params[param_index] = param_name_p;
}
JERRY_ASSERT (param_index == formal_params_number);
for (int32_t indx = (int32_t) formal_params_number - 1;
indx >= 0;
indx--)
for (uint32_t indx = 0;
indx < formal_params_number;
indx++)
{
// i.
ecma_string_t *name_p = formal_params[indx];
bool is_first_occurence = true;
// ii.
for (int32_t indx2 = indx + 1;
indx2 < (int32_t) formal_params_number;
indx2++)
if (literal_p[indx].packed_value == MEM_CP_NULL)
{
if (ecma_compare_ecma_strings (name_p, formal_params[indx2]))
{
is_first_occurence = false;
break;
}
continue;
}
if (is_first_occurence)
{
ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 ((uint32_t) indx);
ecma_string_t *name_p = ecma_new_ecma_string_from_lit_cp (literal_p[indx]);
ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 ((uint32_t) indx);
prop_desc.is_value_defined = true;
prop_desc.value = ecma_make_string_value (name_p);
prop_desc.is_value_defined = true;
prop_desc.value = ecma_make_string_value (name_p);
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = true;
prop_desc.is_configurable_defined = true;
prop_desc.is_configurable = true;
completion = ecma_op_object_define_own_property (map_p,
indx_string_p,
&prop_desc,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
completion = ecma_op_object_define_own_property (map_p,
indx_string_p,
&prop_desc,
false);
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
ecma_deref_ecma_string (indx_string_p);
}
ecma_deref_ecma_string (indx_string_p);
ecma_deref_ecma_string (name_p);
}
MEM_FINALIZE_LOCAL_ARRAY (formal_params);
// 12.
ecma_set_object_type (obj_p, ECMA_OBJECT_TYPE_ARGUMENTS);
@@ -264,9 +213,138 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function
ecma_deref_object (thrower_p);
}
return obj_p;
ecma_string_t *arguments_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
if (is_strict)
{
ecma_op_create_immutable_binding (lex_env_p, arguments_string_p);
ecma_op_initialize_immutable_binding (lex_env_p,
arguments_string_p,
ecma_make_object_value (obj_p));
}
else
{
ecma_completion_value_t completion = ecma_op_create_mutable_binding (lex_env_p,
arguments_string_p,
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
completion = ecma_op_set_mutable_binding (lex_env_p,
arguments_string_p,
ecma_make_object_value (obj_p),
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
}
ecma_deref_ecma_string (arguments_string_p);
ecma_deref_object (obj_p);
} /* ecma_op_create_arguments_object_common */
/**
* Arguments object creation operation.
*
* See also: ECMA-262 v5, 10.6
*
* @return pointer to newly created Arguments object
*/
void
ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function */
ecma_object_t *lex_env_p, /**< lexical environment the Arguments
object is created for */
ecma_collection_header_t *arg_collection_p, /**< arguments collection */
const ecma_compiled_code_t *bytecode_data_p) /**< byte code */
{
const ecma_length_t arguments_number = arg_collection_p != NULL ? arg_collection_p->unit_number : 0;
// 2., 3., 6.
ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
ecma_object_t *obj_p = ecma_create_object (prototype_p, true, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (prototype_p);
// 11.a, 11.b
ecma_collection_iterator_t args_iterator;
ecma_collection_iterator_init (&args_iterator, arg_collection_p);
for (ecma_length_t indx = 0;
indx < arguments_number;
indx++)
{
ecma_completion_value_t completion;
bool is_moved = ecma_collection_iterator_next (&args_iterator);
JERRY_ASSERT (is_moved);
ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx);
completion = ecma_builtin_helper_def_prop (obj_p,
indx_string_p,
*args_iterator.current_value_p,
true, /* Writable */
true, /* Enumerable */
true, /* Configurable */
false); /* Failure handling */
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
ecma_deref_ecma_string (indx_string_p);
}
ecma_op_create_arguments_object_common (obj_p,
func_obj_p,
lex_env_p,
arguments_number,
bytecode_data_p);
} /* ecma_op_create_arguments_object */
/**
* Arguments object creation operation.
*
* See also: ECMA-262 v5, 10.6
*/
void
ecma_op_create_arguments_object_array_args (ecma_object_t *func_obj_p, /**< callee function */
ecma_object_t *lex_env_p, /**< lexical environment the Arguments
object is created for */
const ecma_value_t *arguments_list_p, /**< arguments list */
ecma_length_t arguments_number, /**< length of arguments list */
const ecma_compiled_code_t *bytecode_data_p) /**< byte code */
{
// 2., 3., 6.
ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
ecma_object_t *obj_p = ecma_create_object (prototype_p, true, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (prototype_p);
// 11.a, 11.b
for (ecma_length_t indx = 0;
indx < arguments_number;
indx++)
{
ecma_completion_value_t completion;
ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx);
completion = ecma_builtin_helper_def_prop (obj_p,
indx_string_p,
arguments_list_p[indx],
true, /* Writable */
true, /* Enumerable */
true, /* Configurable */
false); /* Failure handling */
JERRY_ASSERT (ecma_is_completion_value_normal_true (completion));
ecma_deref_ecma_string (indx_string_p);
}
ecma_op_create_arguments_object_common (obj_p,
func_obj_p,
lex_env_p,
arguments_number,
bytecode_data_p);
} /* ecma_op_create_arguments_object_array_args */
/**
* Get value of function's argument mapped to index of Arguments object.
*
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,13 @@
#include "ecma-globals.h"
#include "ecma-helpers.h"
extern ecma_object_t *
extern void
ecma_op_create_arguments_object (ecma_object_t *, ecma_object_t *,
ecma_collection_header_t *, ecma_collection_header_t *, bool);
ecma_collection_header_t *, const ecma_compiled_code_t *);
extern void
ecma_op_create_arguments_object_array_args (ecma_object_t *, ecma_object_t *, const ecma_value_t *,
ecma_length_t, const ecma_compiled_code_t *);
extern ecma_completion_value_t
ecma_op_arguments_object_get (ecma_object_t *, ecma_string_t *);
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@
*/
ecma_completion_value_t
re_parse_regexp_flags (ecma_string_t *flags_str_p, /**< Input string with flags */
uint8_t *flags_p) /**< Output: parsed flag bits */
uint16_t *flags_p) /**< Output: parsed flag bits */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
@@ -129,7 +129,7 @@ re_parse_regexp_flags (ecma_string_t *flags_str_p, /**< Input string with flags
void
re_initialize_props (ecma_object_t *re_obj_p, /**< RegExp obejct */
ecma_string_t *source_p, /**< source string */
uint8_t flags) /**< flags */
uint16_t flags) /**< flags */
{
/* Set source property. ECMA-262 v5, 15.10.7.1 */
ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
@@ -218,6 +218,42 @@ re_initialize_props (ecma_object_t *re_obj_p, /**< RegExp obejct */
ecma_dealloc_number (lastindex_num_p);
} /* re_initialize_props */
/**
* RegExp object creation operation.
*
* See also: ECMA-262 v5, 15.10.4.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_value_t
ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p) /**< input pattern */
{
JERRY_ASSERT (bytecode_p != NULL);
ecma_object_t *re_prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE);
ecma_object_t *obj_p = ecma_create_object (re_prototype_obj_p, true, ECMA_OBJECT_TYPE_GENERAL);
ecma_deref_object (re_prototype_obj_p);
/* Set the internal [[Class]] property */
ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS);
class_prop_p->u.internal_property.value = LIT_MAGIC_STRING_REGEXP_UL;
/* Set bytecode internal property. */
ecma_property_t *bytecode_prop_p;
bytecode_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
ECMA_SET_NON_NULL_POINTER (bytecode_prop_p->u.internal_property.value, bytecode_p);
ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_p);
/* Initialize RegExp object properties */
re_initialize_props (obj_p,
ECMA_GET_NON_NULL_POINTER (ecma_string_t, bytecode_p->pattern_cp),
bytecode_p->flags);
return ecma_make_object_value (obj_p);
} /* ecma_op_create_regexp_object_from_bytecode */
/**
* RegExp object creation operation.
*
@@ -232,7 +268,7 @@ ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */
{
JERRY_ASSERT (pattern_p != NULL);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
uint8_t flags = 0;
uint16_t flags = 0;
if (flags_str_p != NULL)
{
@@ -261,7 +297,7 @@ ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */
bytecode_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
/* Compile bytecode. */
re_bytecode_t *bc_p = NULL;
re_compiled_code_t *bc_p = NULL;
ECMA_TRY_CATCH (empty, re_compile_bytecode (&bc_p, pattern_p, flags), ret_value);
ECMA_SET_POINTER (bytecode_prop_p->u.internal_property.value, bc_p);
@@ -336,7 +372,7 @@ re_canonicalize (ecma_char_t ch, /**< character */
*/
static ecma_completion_value_t
re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
re_bytecode_t *bc_p, /**< pointer to the current RegExp bytecode */
uint8_t *bc_p, /**< pointer to the current RegExp bytecode */
lit_utf8_byte_t *str_p, /**< input string pointer */
lit_utf8_byte_t **out_str_p) /**< Output: matching substring iterator */
{
@@ -651,7 +687,7 @@ re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
}
case RE_OP_SAVE_AT_START:
{
re_bytecode_t *old_bc_p;
uint8_t *old_bc_p;
JERRY_DDLOG ("Execute RE_OP_SAVE_AT_START\n");
lit_utf8_byte_t *old_start_p = re_ctx_p->saved_p[RE_GLOBAL_START_IDX];
@@ -717,7 +753,7 @@ re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
uint32_t start_idx, iter_idx, offset;
lit_utf8_byte_t *old_start_p = NULL;
lit_utf8_byte_t *sub_str_p = NULL;
re_bytecode_t *old_bc_p;
uint8_t *old_bc_p;
old_bc_p = bc_p; /* save the bytecode start position of the group start */
start_idx = re_get_value (&bc_p);
@@ -770,8 +806,8 @@ re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
{
uint32_t start_idx, iter_idx, old_iteration_cnt, offset;
lit_utf8_byte_t *sub_str_p = NULL;
re_bytecode_t *old_bc_p;
re_bytecode_t *end_bc_p = NULL;
uint8_t *old_bc_p;
uint8_t *end_bc_p = NULL;
start_idx = re_get_value (&bc_p);
if (op != RE_OP_CAPTURE_GROUP_START
@@ -844,7 +880,7 @@ re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
case RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END:
{
uint32_t end_idx, iter_idx, min, max;
re_bytecode_t *old_bc_p;
uint8_t *old_bc_p;
/*
* On non-greedy iterations we have to execute the bytecode
@@ -904,7 +940,7 @@ re_match_regexp (re_matcher_ctx_t *re_ctx_p, /**< RegExp matcher context */
lit_utf8_byte_t *old_start_p = NULL;
lit_utf8_byte_t *old_end_p = NULL;
lit_utf8_byte_t *sub_str_p = NULL;
re_bytecode_t *old_bc_p;
uint8_t *old_bc_p;
end_idx = re_get_value (&bc_p);
min = re_get_value (&bc_p);
@@ -1217,7 +1253,8 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
ecma_property_t *bytecode_prop_p = ecma_get_internal_property (regexp_object_p,
ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
re_bytecode_t *bc_p = ECMA_GET_POINTER (re_bytecode_t, bytecode_prop_p->u.internal_property.value);
re_compiled_code_t *bc_p = ECMA_GET_POINTER (re_compiled_code_t,
bytecode_prop_p->u.internal_property.value);
ecma_string_t *input_string_p = ecma_get_string_from_value (input_string);
lit_utf8_size_t input_string_size = ecma_string_get_size (input_string_p);
@@ -1240,11 +1277,11 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
re_ctx.input_end_p = input_buffer_p + input_string_size;
/* 1. Read bytecode header and init regexp matcher context. */
re_ctx.flags = (uint8_t) re_get_value (&bc_p);
re_ctx.flags = bc_p->flags;
if (ignore_global)
{
re_ctx.flags &= (uint8_t) ~RE_FLAG_GLOBAL;
re_ctx.flags &= (uint16_t) ~RE_FLAG_GLOBAL;
}
JERRY_DDLOG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n",
@@ -1252,10 +1289,9 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
re_ctx.flags & RE_FLAG_IGNORE_CASE,
re_ctx.flags & RE_FLAG_MULTILINE);
re_ctx.num_of_captures = re_get_value (&bc_p);
re_ctx.num_of_captures = bc_p->num_of_captures;
JERRY_ASSERT (re_ctx.num_of_captures % 2 == 0);
re_ctx.num_of_non_captures = re_get_value (&bc_p);
re_ctx.num_of_non_captures = bc_p->num_of_non_captures;
MEM_DEFINE_LOCAL_ARRAY (saved_p, re_ctx.num_of_captures + re_ctx.num_of_non_captures, lit_utf8_byte_t *);
@@ -1301,6 +1337,7 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
/* 2. Try to match */
lit_utf8_byte_t *sub_str_p = NULL;
uint8_t *bc_start_p = (uint8_t *) (bc_p + 1);
while (ecma_is_completion_value_empty (ret_value))
{
@@ -1321,7 +1358,12 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
}
else
{
ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx, bc_p, input_curr_p, &sub_str_p), ret_value);
ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx,
bc_start_p,
input_curr_p,
&sub_str_p),
ret_value);
if (ecma_is_value_true (match_value))
{
is_match = true;
@@ -1346,7 +1388,7 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */
if (sub_str_p)
{
*lastindex_num_p = lit_utf8_string_length (input_buffer_p,
(lit_utf8_size_t) (sub_str_p - input_buffer_p));
(lit_utf8_size_t) (sub_str_p - input_buffer_p));
}
else
{
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,9 +32,9 @@
/**
* RegExp flags
*/
#define RE_FLAG_GLOBAL (1 << 0) /* ECMA-262 v5, 15.10.7.2 */
#define RE_FLAG_IGNORE_CASE (1 << 1) /* ECMA-262 v5, 15.10.7.3 */
#define RE_FLAG_MULTILINE (1 << 2) /* ECMA-262 v5, 15.10.7.4 */
#define RE_FLAG_GLOBAL (1 << 1) /* ECMA-262 v5, 15.10.7.2 */
#define RE_FLAG_IGNORE_CASE (1 << 2) /* ECMA-262 v5, 15.10.7.3 */
#define RE_FLAG_MULTILINE (1 << 3) /* ECMA-262 v5, 15.10.7.4 */
/**
* RegExp executor context
@@ -47,9 +47,12 @@ typedef struct
uint32_t num_of_captures; /**< number of capture groups */
uint32_t num_of_non_captures; /**< number of non-capture groups */
uint32_t *num_of_iterations_p; /**< number of iterations */
uint8_t flags; /**< RegExp flags */
uint16_t flags; /**< RegExp flags */
} re_matcher_ctx_t;
extern ecma_value_t
ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *);
extern ecma_completion_value_t
ecma_op_create_regexp_object (ecma_string_t *, ecma_string_t *);
@@ -62,10 +65,10 @@ extern void
re_set_result_array_properties (ecma_object_t *, ecma_string_t *, uint32_t, int32_t);
extern ecma_completion_value_t
re_parse_regexp_flags (ecma_string_t *, uint8_t *);
re_parse_regexp_flags (ecma_string_t *, uint16_t *);
extern void
re_initialize_props (ecma_object_t *, ecma_string_t *, uint8_t);
re_initialize_props (ecma_object_t *, ecma_string_t *, uint16_t);
/**
* @}
-17
View File
@@ -32,21 +32,4 @@ jerry_dispatch_object_free_callback (ecma_external_pointer_t, ecma_external_poin
extern bool
jerry_is_abort_on_fail (void);
/**
* Snapshot header
*/
typedef struct
{
uint32_t lit_table_size; /**< size of literal table */
uint32_t scopes_num; /**< number of saved bytecode pieces in the snapshot */
uint32_t is_run_global : 1; /**< flag, indicating whether the snapshot
* was dumped as 'Global scope'-mode code (true)
* or as eval-mode code (false) */
} jerry_snapshot_header_t;
/**
* Jerry snapshot format version
*/
#define JERRY_SNAPSHOT_VERSION (2u)
#endif /* !JERRY_INTERNAL_H */
+50
View File
@@ -0,0 +1,50 @@
/* Copyright 2016 University of Szeged.
* Copyright 2016 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef JERRY_SNAPSHOT_H
#define JERRY_SNAPSHOT_H
#include "ecma-globals.h"
/**
* Snapshot header
*/
typedef struct
{
uint32_t last_compiled_code_offset; /**< offset of the last compiled code */
uint32_t lit_table_size; /**< size of literal table */
uint32_t is_run_global : 1; /**< flag, indicating whether the snapshot
* was dumped as 'Global scope'-mode code (true)
* or as eval-mode code (false) */
} jerry_snapshot_header_t;
/**
* Jerry snapshot format version
*/
#define JERRY_SNAPSHOT_VERSION (3u)
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/* Snapshot support functions */
extern bool snapshot_report_byte_code_compilation;
extern void
snapshot_add_compiled_code (ecma_compiled_code_t *, const uint8_t *, uint32_t);
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#endif /* !JERRY_SNAPSHOT_H */
+474 -114
View File
@@ -1,4 +1,4 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
#include <stdio.h>
#include "bytecode-data.h"
#include "ecma-alloc.h"
#include "ecma-array-object.h"
#include "ecma-builtins.h"
@@ -28,8 +27,12 @@
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#include "ecma-try-catch-macro.h"
#include "jerry-snapshot.h"
#include "lit-literal.h"
#include "lit-magic-strings.h"
#include "lit-snapshot.h"
#include "parser.h"
#include "re-compiler.h"
#define JERRY_INTERNAL
#include "jerry-internal.h"
@@ -685,7 +688,7 @@ jerry_api_create_string (const jerry_api_char_t *v) /**< string value */
*/
jerry_api_string_t *
jerry_api_create_string_sz (const jerry_api_char_t *v, /**< string value */
jerry_api_size_t v_size)
jerry_api_size_t v_size) /**< string size */
{
jerry_assert_api_available ();
@@ -1125,9 +1128,9 @@ jerry_api_delete_object_field (jerry_api_object_t *object_p, /**< object to dele
* - there is field with specified name in the object;
* false - otherwise.
*/
bool jerry_api_get_object_field_value (jerry_api_object_t *object_p,
const jerry_api_char_t *field_name_p,
jerry_api_value_t *field_value_p)
bool jerry_api_get_object_field_value (jerry_api_object_t *object_p, /**< object */
const jerry_api_char_t *field_name_p, /**< field name */
jerry_api_value_t *field_value_p) /**< out: field value */
{
return jerry_api_get_object_field_value_sz (object_p,
field_name_p,
@@ -1672,9 +1675,8 @@ jerry_cleanup (void)
ecma_finalize ();
lit_finalize ();
bc_finalize ();
mem_finalize (is_show_mem_stats);
vm_finalize ();
mem_finalize (is_show_mem_stats);
} /* jerry_cleanup */
/**
@@ -1724,11 +1726,11 @@ jerry_parse (const jerry_api_char_t* source_p, /**< script source */
{
jerry_assert_api_available ();
bool is_show_instructions = ((jerry_flags & JERRY_FLAG_SHOW_OPCODES) != 0);
int is_show_instructions = ((jerry_flags & JERRY_FLAG_SHOW_OPCODES) != 0);
parser_set_show_instrs (is_show_instructions);
const bytecode_data_header_t *bytecode_data_p;
ecma_compiled_code_t *bytecode_data_p;
jsp_status_t parse_status;
parse_status = parser_parse_script (source_p,
@@ -1865,6 +1867,212 @@ jerry_register_external_magic_strings (const jerry_api_char_ptr_t* ex_str_items,
lit_magic_strings_ex_set ((const lit_utf8_byte_t **) ex_str_items, count, (const lit_utf8_size_t *) str_lengths);
} /* jerry_register_external_magic_strings */
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/*
* Tells whether snapshot taking is in progress.
*/
bool snapshot_report_byte_code_compilation = false;
/*
* Mapping snapshot to offset.
*/
typedef struct
{
mem_cpointer_t next_cp;
mem_cpointer_t compiled_code_cp;
uint16_t offset;
} compiled_code_map_entry_t;
/*
* Variables required to take a snapshot.
*/
static size_t snapshot_buffer_write_offset;
static size_t snapshot_last_compiled_code_offset;
static bool snapshot_error_occured;
static uint8_t *snapshot_buffer_p;
static size_t snapshot_buffer_size;
static compiled_code_map_entry_t *snapshot_map_entries_p;
/**
* Snapshot callback for byte codes.
*/
void
snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */
const uint8_t *regexp_pattern, /**< regular expression pattern */
uint32_t size) /**< compiled code or regular expression size */
{
if (snapshot_error_occured)
{
return;
}
JERRY_ASSERT ((snapshot_buffer_write_offset & (MEM_ALIGNMENT - 1)) == 0);
if ((snapshot_buffer_write_offset >> MEM_ALIGNMENT_LOG) > 0xffffu)
{
snapshot_error_occured = true;
return;
}
snapshot_last_compiled_code_offset = snapshot_buffer_write_offset;
compiled_code_map_entry_t *new_entry = (compiled_code_map_entry_t *) mem_pools_alloc ();
if (new_entry == NULL)
{
snapshot_error_occured = true;
return;
}
ECMA_SET_POINTER (new_entry->next_cp, snapshot_map_entries_p);
ECMA_SET_POINTER (new_entry->compiled_code_cp, compiled_code_p);
new_entry->offset = (uint16_t) (snapshot_buffer_write_offset >> MEM_ALIGNMENT_LOG);
snapshot_map_entries_p = new_entry;
const void *data_p = (const void *) compiled_code_p;
if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
{
size += (uint32_t) sizeof (uint16_t);
}
else
{
JERRY_ASSERT (regexp_pattern == NULL);
}
if (!jrt_write_to_buffer_by_offset (snapshot_buffer_p,
snapshot_buffer_size,
&snapshot_buffer_write_offset,
&size,
sizeof (uint32_t)))
{
snapshot_error_occured = true;
return;
}
if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
{
size -= (uint32_t) sizeof (uint16_t);
if (!jrt_write_to_buffer_by_offset (snapshot_buffer_p,
snapshot_buffer_size,
&snapshot_buffer_write_offset,
&compiled_code_p->status_flags,
sizeof (uint16_t)))
{
snapshot_error_occured = true;
return;
}
data_p = regexp_pattern;
}
if (!jrt_write_to_buffer_by_offset (snapshot_buffer_p,
snapshot_buffer_size,
&snapshot_buffer_write_offset,
data_p,
size))
{
snapshot_error_occured = true;
return;
}
snapshot_buffer_write_offset = JERRY_ALIGNUP (snapshot_buffer_write_offset, MEM_ALIGNMENT);
if (snapshot_buffer_write_offset > snapshot_buffer_size)
{
snapshot_error_occured = true;
return;
}
} /* snapshot_add_compiled_code */
/**
* Set the uint16_t offsets in the code area.
*/
static void
jerry_snapshot_set_offsets (uint8_t *buffer_p, /**< buffer */
uint32_t size, /**< buffer size */
lit_mem_to_snapshot_id_map_entry_t *lit_map_p) /**< literal map */
{
JERRY_ASSERT (size > 0);
do
{
uint32_t code_size = *(uint32_t *) buffer_p;
buffer_p += sizeof (uint32_t);
ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
/* Set reference counter to 1. */
bytecode_p->status_flags &= (1 << ECMA_BYTECODE_REF_SHIFT) - 1;
bytecode_p->status_flags |= 1 << ECMA_BYTECODE_REF_SHIFT;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
{
lit_cpointer_t *literal_start_p;
uint32_t literal_end;
uint32_t const_literal_end;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
literal_start_p = (lit_cpointer_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
}
else
{
literal_start_p = (lit_cpointer_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
}
for (uint32_t i = 0; i < const_literal_end; i++)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
if (literal_start_p[i].packed_value != MEM_CP_NULL)
{
while (current_p->literal_id.packed_value != literal_start_p[i].packed_value)
{
current_p++;
}
literal_start_p[i].packed_value = (uint16_t) current_p->literal_offset;
}
}
for (uint32_t i = const_literal_end; i < literal_end; i++)
{
compiled_code_map_entry_t *current_p = snapshot_map_entries_p;
while (current_p->compiled_code_cp != literal_start_p[i].value.base_cp)
{
current_p = ECMA_GET_NON_NULL_POINTER (compiled_code_map_entry_t,
current_p->next_cp);
}
literal_start_p[i].packed_value = (uint16_t) current_p->offset;
}
}
code_size += (uint32_t) sizeof (uint32_t);
code_size = JERRY_ALIGNUP (code_size, MEM_ALIGNMENT);
buffer_p += code_size - sizeof (uint32_t);
size -= code_size;
}
while (size > 0);
} /* jerry_snapshot_set_offsets */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
/**
* Generate snapshot from specified source
*
@@ -1881,9 +2089,41 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou
uint8_t *buffer_p, /**< buffer to dump snapshot to */
size_t buffer_size) /**< the buffer's size */
{
#ifdef JERRY_ENABLE_SNAPSHOT
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
jsp_status_t parse_status;
const bytecode_data_header_t *bytecode_data_p;
ecma_compiled_code_t *bytecode_data_p;
snapshot_buffer_write_offset = 0;
snapshot_last_compiled_code_offset = 0;
snapshot_error_occured = false;
snapshot_buffer_p = buffer_p;
snapshot_buffer_size = buffer_size;
snapshot_map_entries_p = NULL;
uint64_t version = JERRY_SNAPSHOT_VERSION;
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&snapshot_buffer_write_offset,
&version,
sizeof (version)))
{
return 0;
}
snapshot_buffer_write_offset = JERRY_ALIGNUP (snapshot_buffer_write_offset, MEM_ALIGNMENT);
size_t header_offset = snapshot_buffer_write_offset;
snapshot_buffer_write_offset += JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT);
if (snapshot_buffer_write_offset > buffer_size)
{
return 0;
}
size_t compiled_code_start = snapshot_buffer_write_offset;
snapshot_report_byte_code_compilation = true;
if (is_for_global)
{
@@ -1891,88 +2131,81 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou
}
else
{
bool code_contains_functions;
parse_status = parser_parse_eval (source_p,
source_size,
false,
&bytecode_data_p,
&code_contains_functions);
&bytecode_data_p);
}
if (parse_status != JSP_STATUS_OK)
snapshot_report_byte_code_compilation = false;
if (parse_status == JSP_STATUS_OK
&& !snapshot_error_occured)
{
return 0;
}
JERRY_ASSERT (snapshot_last_compiled_code_offset != 0);
size_t buffer_write_offset = 0;
jerry_snapshot_header_t header;
header.last_compiled_code_offset = (uint32_t) snapshot_last_compiled_code_offset;
header.is_run_global = is_for_global;
jerry_snapshot_header_t header;
header.is_run_global = is_for_global;
size_t compiled_code_size = snapshot_buffer_write_offset - compiled_code_start;
uint64_t version = JERRY_SNAPSHOT_VERSION;
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&buffer_write_offset,
&version,
sizeof (version)))
{
return 0;
}
lit_mem_to_snapshot_id_map_entry_t* lit_map_p = NULL;
uint32_t literals_num;
size_t header_offset = buffer_write_offset;
if (!lit_dump_literals_for_snapshot (buffer_p,
buffer_size,
&snapshot_buffer_write_offset,
&lit_map_p,
&literals_num,
&header.lit_table_size))
{
JERRY_ASSERT (lit_map_p == NULL);
snapshot_buffer_write_offset = 0;
}
else
{
if (header.lit_table_size > 0xffff)
{
/* Aligning literals could increase this range, but
* it is not a requirement for low-memory environments. */
snapshot_buffer_write_offset = 0;
}
else
{
jerry_snapshot_set_offsets (buffer_p + compiled_code_start,
(uint32_t) compiled_code_size,
lit_map_p);
if (buffer_write_offset + JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT) > buffer_size)
{
return 0;
}
buffer_write_offset += JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT);
lit_mem_to_snapshot_id_map_entry_t* lit_map_p = NULL;
uint32_t literals_num;
if (!lit_dump_literals_for_snapshot (buffer_p,
jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&buffer_write_offset,
&lit_map_p,
&literals_num,
&header.lit_table_size))
&header_offset,
&header,
sizeof (header));
}
mem_heap_free_block (lit_map_p);
}
ecma_bytecode_deref (bytecode_data_p);
}
else
{
JERRY_ASSERT (lit_map_p == NULL);
return 0;
snapshot_buffer_write_offset = 0;
}
size_t bytecode_offset = (sizeof (version)
+ JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT)
+ header.lit_table_size);
compiled_code_map_entry_t *current_p = snapshot_map_entries_p;
JERRY_ASSERT (JERRY_ALIGNUP (bytecode_offset, MEM_ALIGNMENT) == bytecode_offset);
bool is_ok = bc_save_bytecode_data (buffer_p,
buffer_size,
&buffer_write_offset,
bytecode_data_p,
lit_map_p,
literals_num,
&header.scopes_num);
JERRY_ASSERT (header.scopes_num != 0);
if (lit_map_p != NULL)
while (current_p != NULL)
{
mem_heap_free_block (lit_map_p);
compiled_code_map_entry_t *next_p = ECMA_GET_POINTER (compiled_code_map_entry_t,
current_p->next_cp);
mem_pools_free ((uint8_t *) current_p);
current_p = next_p;
}
if (!is_ok)
{
return 0;
}
is_ok = jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &header_offset, &header, sizeof (header));
JERRY_ASSERT (is_ok && header_offset < buffer_write_offset);
return buffer_write_offset;
#else /* JERRY_ENABLE_SNAPSHOT */
return snapshot_buffer_write_offset;
#else /* JERRY_ENABLE_SNAPSHOT_SAVE */
(void) source_p;
(void) source_size;
(void) is_for_global;
@@ -1980,9 +2213,144 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou
(void) buffer_size;
return 0;
#endif /* !JERRY_ENABLE_SNAPSHOT */
#endif /* !JERRY_ENABLE_SNAPSHOT_SAVE */
} /* jerry_parse_and_save_snapshot */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
/**
* Load byte code from snapshot.
*
* @return byte code
*/
static ecma_compiled_code_t *
snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data */
size_t offset, /**< byte code offset */
lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
bool copy_bytecode) /**< byte code should be copied to memory */
{
uint32_t code_size = *(uint32_t *) (snapshot_data_p + offset);
ecma_compiled_code_t *bytecode_p;
bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + offset + sizeof (uint32_t));
if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
{
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
re_compiled_code_t *re_bytecode_p = NULL;
const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (uint16_t);
code_size -= (uint32_t) sizeof (uint16_t);
ecma_string_t *pattern_str_p = ecma_new_ecma_string_from_utf8 (regex_start_p,
code_size);
re_compile_bytecode (&re_bytecode_p,
pattern_str_p,
bytecode_p->status_flags);
ecma_deref_ecma_string (pattern_str_p);
return (ecma_compiled_code_t *) re_bytecode_p;
#else
JERRY_UNIMPLEMENTED ("RegExp is not supported in compact profile.");
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
}
size_t header_size;
uint32_t literal_end;
uint32_t const_literal_end;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
header_size = sizeof (cbc_uint16_arguments_t);
}
else
{
uint8_t *byte_p = (uint8_t *) bytecode_p;
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p;
literal_end = args_p->literal_end;
const_literal_end = args_p->const_literal_end;
header_size = sizeof (cbc_uint8_arguments_t);
}
if (copy_bytecode)
{
bytecode_p = (ecma_compiled_code_t *) mem_heap_alloc_block (code_size,
MEM_HEAP_ALLOC_LONG_TERM);
memcpy (bytecode_p, snapshot_data_p + offset + sizeof (uint32_t), code_size);
}
else
{
code_size = (uint32_t) (header_size + literal_end * sizeof (lit_cpointer_t));
uint8_t *real_bytecode_p = ((uint8_t *) bytecode_p) + code_size;
bytecode_p = (ecma_compiled_code_t *) mem_heap_alloc_block (code_size + 1 + sizeof (uint8_t *),
MEM_HEAP_ALLOC_LONG_TERM);
memcpy (bytecode_p, snapshot_data_p + offset + sizeof (uint32_t), code_size);
uint8_t *instructions_p = ((uint8_t *) bytecode_p);
instructions_p[code_size] = CBC_SET_BYTECODE_PTR;
memcpy (instructions_p + code_size + 1, &real_bytecode_p, sizeof (uint8_t *));
}
JERRY_ASSERT ((bytecode_p->status_flags >> ECMA_BYTECODE_REF_SHIFT) == 1);
lit_cpointer_t *literal_start_p = (lit_cpointer_t *) (((uint8_t *) bytecode_p) + header_size);
for (uint32_t i = 0; i < const_literal_end; i++)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
if (literal_start_p[i].packed_value != 0)
{
while (current_p->literal_offset != literal_start_p[i].packed_value)
{
current_p++;
}
literal_start_p[i] = current_p->literal_id;
}
}
for (uint32_t i = const_literal_end; i < literal_end; i++)
{
size_t literal_offset = ((size_t) literal_start_p[i].packed_value) << MEM_ALIGNMENT_LOG;
if (literal_offset == offset)
{
/* Self reference */
ECMA_SET_NON_NULL_POINTER (literal_start_p[i].value.base_cp,
bytecode_p);
}
else
{
ecma_compiled_code_t *literal_bytecode_p;
literal_bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
literal_offset,
lit_map_p,
copy_bytecode);
ECMA_SET_NON_NULL_POINTER (literal_start_p[i].value.base_cp,
literal_bytecode_p);
}
}
return bytecode_p;
} /* snapshot_load_compiled_code */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
/**
* Execute snapshot from specified buffer
*
@@ -1991,19 +2359,19 @@ jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script sou
jerry_completion_code_t
jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
size_t snapshot_size, /**< size of snapshot */
bool is_copy, /**< flag, indicating whether the passed snapshot
* buffer should be copied to engine's memory,
* so engine should not reference the buffer
* after the function returns (in the case, the passed
* buffer could be freed after the call);
* otherwise (if flag not set) - the buffer could be freed
* only after engine stops (i.e. after call to jerry_cleanup). */
jerry_api_value_t *retval_p) /**< out: returned value (ECMA-262 'undefined' if code is executed
* as global scope code) */
bool copy_bytecode, /**< flag, indicating whether the passed snapshot
* buffer should be copied to the engine's memory.
* If set the engine should not reference the buffer
* after the function returns (in this case, the passed
* buffer could be freed after the call).
* Otherwise (if the flag is not set) - the buffer could only be
* freed after the engine stops (i.e. after call to jerry_cleanup). */
jerry_api_value_t *retval_p) /**< out: returned value (ECMA-262 'undefined' if
* code is executed as global scope code) */
{
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
#ifdef JERRY_ENABLE_SNAPSHOT
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
JERRY_ASSERT (snapshot_p != NULL);
const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
@@ -2025,21 +2393,20 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
}
const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) (snapshot_data_p + snapshot_read);
if (snapshot_read + JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT) > snapshot_size)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
snapshot_read += JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t), MEM_ALIGNMENT);
snapshot_read = header_p->last_compiled_code_offset;
if (snapshot_read + header_p->lit_table_size > snapshot_size)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
JERRY_ASSERT (snapshot_read == JERRY_ALIGNUP (snapshot_read, MEM_ALIGNMENT));
uint32_t last_code_size = *(uint32_t *) (snapshot_data_p + snapshot_read);
snapshot_read += JERRY_ALIGNUP (last_code_size + sizeof (uint32_t), MEM_ALIGNMENT);
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
uint32_t literals_num;
JERRY_ASSERT (snapshot_read + header_p->lit_table_size <= snapshot_size);
if (!lit_load_literals_from_snapshot (snapshot_data_p + snapshot_read,
header_p->lit_table_size,
&lit_map_p,
@@ -2049,28 +2416,21 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
snapshot_read += header_p->lit_table_size;
ecma_compiled_code_t *bytecode_p;
if (snapshot_read > snapshot_size)
{
mem_heap_free_block (lit_map_p);
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
snapshot_read = header_p->last_compiled_code_offset;
const bytecode_data_header_t *bytecode_data_p;
bytecode_data_p = bc_load_bytecode_data (snapshot_data_p + snapshot_read,
snapshot_size - snapshot_read,
lit_map_p,
literals_num,
is_copy,
header_p->scopes_num);
bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
snapshot_read,
lit_map_p,
copy_bytecode);
if (lit_map_p != NULL)
{
mem_heap_free_block (lit_map_p);
}
if (bytecode_data_p == NULL)
if (bytecode_p == NULL)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
@@ -2079,7 +2439,7 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
if (header_p->is_run_global)
{
vm_init (bytecode_data_p, false);
vm_init (bytecode_p, false);
ret_code = vm_run_global ();
@@ -2088,7 +2448,7 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
else
{
/* vm should be already initialized */
ecma_completion_value_t completion = vm_run_eval (bytecode_data_p, false);
ecma_completion_value_t completion = vm_run_eval (bytecode_p, false);
ret_code = jerry_api_convert_eval_completion_to_retval (retval_p, completion);
@@ -2096,12 +2456,12 @@ jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
}
return ret_code;
#else /* JERRY_ENABLE_SNAPSHOT */
#else /* JERRY_ENABLE_SNAPSHOT_EXEC */
(void) snapshot_p;
(void) snapshot_size;
(void) is_copy;
(void) copy_bytecode;
(void) retval_p;
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_VERSION;
#endif /* !JERRY_ENABLE_SNAPSHOT */
#endif /* !JERRY_ENABLE_SNAPSHOT_EXEC */
} /* jerry_exec_snapshot */
+1 -1
View File
@@ -268,7 +268,7 @@ jrt_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */
size_t buffer_size, /**< size of buffer */
size_t *in_out_buffer_offset_p, /**< in: offset to read from,
* out: offset, incremented on sizeof (T) */
void *data_p, /**< data */
const void *data_p, /**< data */
size_t data_size) /**< size of the writable data */
{
if (*in_out_buffer_offset_p + data_size > buffer_size)
+6 -2
View File
@@ -22,7 +22,7 @@
#include "rcs-iterator.h"
#include "rcs-records.h"
#ifdef JERRY_ENABLE_SNAPSHOT
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/**
* Dump a record to specified snapshot buffer.
@@ -250,6 +250,10 @@ lit_dump_literals_for_snapshot (uint8_t *buffer_p, /**< output snapshot buffer *
return true;
} /* lit_dump_literals_for_snapshot */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
/**
* Load literals from snapshot.
*
@@ -408,4 +412,4 @@ lit_load_literals_from_snapshot (const uint8_t *lit_table_p, /**< buffer with li
return false;
} /* rcs_load_literals_from_snapshot */
#endif /* JERRY_ENABLE_SNAPSHOT */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
+4 -2
View File
@@ -25,7 +25,7 @@ typedef struct
uint32_t literal_offset;
} lit_mem_to_snapshot_id_map_entry_t;
#ifdef JERRY_ENABLE_SNAPSHOT
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
extern bool
lit_dump_literals_for_snapshot (uint8_t *,
size_t,
@@ -33,12 +33,14 @@ lit_dump_literals_for_snapshot (uint8_t *,
lit_mem_to_snapshot_id_map_entry_t **,
uint32_t *,
uint32_t *);
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
extern bool
lit_load_literals_from_snapshot (const uint8_t *,
uint32_t,
lit_mem_to_snapshot_id_map_entry_t **,
uint32_t *);
#endif /* JERRY_ENABLE_SNAPSHOT */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
#endif /* !RCS_SNAPSHOT_H */
+6 -6
View File
@@ -1,4 +1,4 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -277,12 +277,12 @@ lit_utf8_iterator_seek_bos (lit_utf8_iterator_t *iter_p) /**< iterator to reset
} /* lit_utf8_iterator_seek_bos */
/**
* Save iterator's position to restore it later
* Get iterator's position
*
* @return current position of the iterator
*/
lit_utf8_iterator_pos_t
lit_utf8_iterator_get_pos (const lit_utf8_iterator_t *iter_p)
lit_utf8_iterator_get_pos (const lit_utf8_iterator_t *iter_p) /**< iterator */
{
return iter_p->buf_pos;
} /* lit_utf8_iterator_get_pos */
@@ -586,7 +586,7 @@ lit_read_code_unit_from_utf8 (const lit_utf8_byte_t *buf_p, /**< buffer with cha
*/
lit_utf8_size_t
lit_read_prev_code_unit_from_utf8 (const lit_utf8_byte_t *buf_p, /**< buffer with characters */
ecma_char_t *code_point) /**< @out: code point */
ecma_char_t *code_point) /**< @out: code point */
{
JERRY_ASSERT (buf_p);
@@ -635,7 +635,7 @@ lit_utf8_read_prev (lit_utf8_byte_t **buf_p) /**< in-out:buffer with characters
* @return next code unit
*/
ecma_char_t
lit_utf8_peek_next (lit_utf8_byte_t *buf_p) /**< in-out:buffer with characters */
lit_utf8_peek_next (const lit_utf8_byte_t *buf_p) /**< in-out:buffer with characters */
{
JERRY_ASSERT (buf_p);
ecma_char_t ch;
@@ -651,7 +651,7 @@ lit_utf8_peek_next (lit_utf8_byte_t *buf_p) /**< in-out:buffer with characters *
* @return previous code unit
*/
ecma_char_t
lit_utf8_peek_prev (lit_utf8_byte_t *buf_p) /**< in-out:buffer with characters */
lit_utf8_peek_prev (const lit_utf8_byte_t *buf_p) /**< in-out:buffer with characters */
{
JERRY_ASSERT (buf_p);
ecma_char_t ch;
+3 -3
View File
@@ -1,4 +1,4 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -183,8 +183,8 @@ lit_utf8_size_t lit_read_prev_code_unit_from_utf8 (const lit_utf8_byte_t *,
ecma_char_t lit_utf8_read_next (lit_utf8_byte_t **);
ecma_char_t lit_utf8_read_prev (lit_utf8_byte_t **);
ecma_char_t lit_utf8_peek_next (lit_utf8_byte_t *);
ecma_char_t lit_utf8_peek_prev (lit_utf8_byte_t *);
ecma_char_t lit_utf8_peek_next (const lit_utf8_byte_t *);
ecma_char_t lit_utf8_peek_prev (const lit_utf8_byte_t *);
void lit_utf8_incr (lit_utf8_byte_t **);
void lit_utf8_decr (lit_utf8_byte_t **);
-834
View File
@@ -1,834 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
*
* 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 "bytecode-data.h"
#include "pretty-printer.h"
#include "opcodes-dumper.h"
/**
* First node of the list of bytecodes
*/
static bytecode_data_header_t *first_bytecode_header_p = NULL;
/**
* Bytecode header in snapshot
*/
typedef struct
{
uint32_t size; /**< size of this bytecode data record */
uint32_t instrs_size; /**< size of instructions array */
uint32_t idx_to_lit_map_size; /**< size of idx-to-lit map */
uint32_t func_scopes_count; /**< count of function scopes inside current scope */
uint32_t var_decls_count; /**< count of variable declarations insdie current scope */
uint8_t is_strict : 1; /**< code is strict mode code */
uint8_t is_ref_arguments_identifier : 1; /**< code doesn't reference 'arguments' identifier */
uint8_t is_ref_eval_identifier : 1; /**< code doesn't reference 'eval' identifier */
uint8_t is_args_moved_to_regs : 1; /**< the function's arguments are moved to registers,
* so should be initialized in vm registers,
* and not in lexical environment */
uint8_t is_no_lex_env : 1; /**< no lex. env. is necessary for the scope */
} jerry_snapshot_bytecode_header_t;
/**
* Fill the fields of bytecode data header with specified values
*/
static void
bc_fill_bytecode_data_header (bytecode_data_header_t *bc_header_p, /**< byte-code scope data header to fill */
lit_id_hash_table *lit_id_hash_table_p, /**< (idx, block id) -> literal hash table */
vm_instr_t *bytecode_p, /**< byte-code instructions array */
mem_cpointer_t *declarations_p, /**< array of function / variable declarations */
uint16_t func_scopes_count, /**< number of function declarations / expressions
* located immediately in the corresponding scope */
uint16_t var_decls_count, /**< number of variable declarations immediately in the scope */
bool is_strict, /**< is the scope's code strict mode code? */
bool is_ref_arguments_identifier, /**< does the scope's code
* reference 'arguments' identifier? */
bool is_ref_eval_identifier, /**< does the scope's code
* reference 'eval' identifier? */
bool is_vars_and_args_to_regs_possible, /**< is it scope, for which variables / arguments
* can be moved to registers */
bool is_arguments_moved_to_regs, /**< is it function scope, for which arguments
* are located on registers, not in variables? */
bool is_no_lex_env) /**< is lexical environment unused in the scope? */
{
MEM_CP_SET_POINTER (bc_header_p->lit_id_hash_cp, lit_id_hash_table_p);
bc_header_p->instrs_p = bytecode_p;
bc_header_p->instrs_count = 0;
MEM_CP_SET_POINTER (bc_header_p->declarations_cp, declarations_p);
bc_header_p->func_scopes_count = func_scopes_count;
bc_header_p->var_decls_count = var_decls_count;
bc_header_p->next_header_cp = MEM_CP_NULL;
bc_header_p->is_strict = is_strict;
bc_header_p->is_ref_arguments_identifier = is_ref_arguments_identifier;
bc_header_p->is_ref_eval_identifier = is_ref_eval_identifier;
bc_header_p->is_vars_and_args_to_regs_possible = is_vars_and_args_to_regs_possible;
bc_header_p->is_args_moved_to_regs = is_arguments_moved_to_regs;
bc_header_p->is_no_lex_env = is_no_lex_env;
} /* bc_fill_bytecode_data_header */
/**
* Free memory occupied by bytecode data
*/
static void
bc_free_bytecode_data (bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
bytecode_data_header_t *next_to_handle_list_p = bytecode_data_p;
while (next_to_handle_list_p != NULL)
{
bytecode_data_header_t *bc_header_list_iter_p = next_to_handle_list_p;
next_to_handle_list_p = NULL;
while (bc_header_list_iter_p != NULL)
{
bytecode_data_header_t *header_p = bc_header_list_iter_p;
bc_header_list_iter_p = MEM_CP_GET_POINTER (bytecode_data_header_t, header_p->next_header_cp);
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, header_p->declarations_cp);
for (uint32_t index = 0; index < header_p->func_scopes_count; index++)
{
bytecode_data_header_t *child_scope_header_p = MEM_CP_GET_NON_NULL_POINTER (bytecode_data_header_t,
declarations_p[index]);
JERRY_ASSERT (child_scope_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (child_scope_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = child_scope_header_p;
}
mem_heap_free_block (header_p);
}
JERRY_ASSERT (bc_header_list_iter_p == NULL);
}
} /* bc_free_bytecode_data */
/**
* Delete bytecode and associated hash table
*/
void
bc_remove_bytecode_data (const bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
bytecode_data_header_t *prev_header_p = NULL;
bytecode_data_header_t *cur_header_p = first_bytecode_header_p;
while (cur_header_p != NULL)
{
if (cur_header_p == bytecode_data_p)
{
if (prev_header_p)
{
prev_header_p->next_header_cp = cur_header_p->next_header_cp;
}
else
{
first_bytecode_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, cur_header_p->next_header_cp);
}
cur_header_p->next_header_cp = MEM_CP_NULL;
bc_free_bytecode_data (cur_header_p);
break;
}
prev_header_p = cur_header_p;
cur_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, cur_header_p->next_header_cp);
}
} /* bc_remove_bytecode_data */
vm_instr_t bc_get_instr (const bytecode_data_header_t *bytecode_data_p, /**< byte-code scope data header */
vm_instr_counter_t oc) /**< instruction position */
{
JERRY_ASSERT (oc < bytecode_data_p->instrs_count);
return bytecode_data_p->instrs_p[oc];
}
/**
* Print bytecode instructions
*/
void
bc_print_instrs (const bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
#ifdef JERRY_ENABLE_PRETTY_PRINTER
for (vm_instr_counter_t loc = 0; loc < bytecode_data_p->instrs_count; loc++)
{
op_meta opm;
opm.op = bytecode_data_p->instrs_p[loc];
for (int i = 0; i < 3; i++)
{
opm.lit_id[i] = NOT_A_LITERAL;
}
pp_op_meta (bytecode_data_p, loc, opm, false);
}
#else
(void) bytecode_data_p;
#endif
} /* bc_print_instrs */
/**
* Dump single scopes tree into bytecode
*
* @return pointer to bytecode header of the outer most scope
*/
bytecode_data_header_t *
bc_dump_single_scope (scopes_tree scope_p) /**< a node of scopes tree */
{
const size_t entries_count = scope_p->max_uniq_literals_num;
const vm_instr_counter_t instrs_count = scopes_tree_instrs_num (scope_p);
const size_t blocks_count = JERRY_ALIGNUP (instrs_count, BLOCK_SIZE) / BLOCK_SIZE;
const size_t func_scopes_count = scopes_tree_child_scopes_num (scope_p);
const uint16_t var_decls_count = linked_list_get_length (scope_p->var_decls);
const size_t bytecode_size = JERRY_ALIGNUP (instrs_count * sizeof (vm_instr_t), MEM_ALIGNMENT);
const size_t hash_table_size = lit_id_hash_table_get_size_for_table (entries_count, blocks_count);
const size_t declarations_area_size = JERRY_ALIGNUP (func_scopes_count * sizeof (mem_cpointer_t)
+ var_decls_count * sizeof (lit_cpointer_t),
MEM_ALIGNMENT);
const size_t header_and_tables_size = JERRY_ALIGNUP ((sizeof (bytecode_data_header_t)
+ hash_table_size
+ declarations_area_size),
MEM_ALIGNMENT);
uint8_t *buffer_p = (uint8_t *) mem_heap_alloc_block (bytecode_size + header_and_tables_size,
MEM_HEAP_ALLOC_LONG_TERM);
lit_id_hash_table *lit_id_hash_p = lit_id_hash_table_init (buffer_p + sizeof (bytecode_data_header_t),
hash_table_size,
entries_count, blocks_count);
mem_cpointer_t *declarations_p = (mem_cpointer_t *) (buffer_p + sizeof (bytecode_data_header_t) + hash_table_size);
for (size_t i = 0; i < func_scopes_count; i++)
{
declarations_p[i] = MEM_CP_NULL;
}
scopes_tree_dump_var_decls (scope_p, (lit_cpointer_t *) (declarations_p + func_scopes_count));
vm_instr_t *bytecode_p = (vm_instr_t *) (buffer_p + header_and_tables_size);
JERRY_ASSERT (scope_p->max_uniq_literals_num >= lit_id_hash_p->current_bucket_pos);
bytecode_data_header_t *header_p = (bytecode_data_header_t *) buffer_p;
if ((uint16_t) func_scopes_count != func_scopes_count)
{
jerry_fatal (ERR_OUT_OF_MEMORY);
}
bc_fill_bytecode_data_header (header_p,
lit_id_hash_p, bytecode_p,
declarations_p,
(uint16_t) func_scopes_count,
var_decls_count,
scope_p->strict_mode,
scope_p->ref_arguments,
scope_p->ref_eval,
scope_p->is_vars_and_args_to_regs_possible,
false,
false);
JERRY_ASSERT (scope_p->bc_header_cp == MEM_CP_NULL);
MEM_CP_SET_NON_NULL_POINTER (scope_p->bc_header_cp, header_p);
return header_p;
} /* bc_dump_single_scope */
void
bc_register_root_bytecode_header (bytecode_data_header_t *bc_header_p)
{
MEM_CP_SET_POINTER (bc_header_p->next_header_cp, first_bytecode_header_p);
first_bytecode_header_p = bc_header_p;
} /* bc_register_root_bytecode_header */
/**
* Free all bytecode data which was allocated
*/
void
bc_finalize (void)
{
while (first_bytecode_header_p != NULL)
{
bytecode_data_header_t *header_p = first_bytecode_header_p;
first_bytecode_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, header_p->next_header_cp);
header_p->next_header_cp = MEM_CP_NULL;
bc_free_bytecode_data (header_p);
}
} /* bc_finalize */
/**
* Convert literal id (operand value of instruction) to compressed pointer to literal
*
* Bytecode is divided into blocks of fixed size and each block has independent encoding of variable names,
* which are represented by 8 bit numbers - ids.
* This function performs conversion from id to literal.
*
* @return compressed pointer to literal
*/
lit_cpointer_t
bc_get_literal_cp_by_uid (uint8_t id, /**< literal idx */
const bytecode_data_header_t *bytecode_data_p, /**< pointer to bytecode */
vm_instr_counter_t oc) /**< position in the bytecode */
{
JERRY_ASSERT (bytecode_data_p);
lit_id_hash_table *lit_id_hash = MEM_CP_GET_POINTER (lit_id_hash_table, bytecode_data_p->lit_id_hash_cp);
if (lit_id_hash == NULL)
{
return INVALID_LITERAL;
}
return lit_id_hash_table_lookup (lit_id_hash, id, oc);
} /* bc_get_literal_cp_by_uid */
#ifdef JERRY_ENABLE_SNAPSHOT
/**
* Find literal offset in the table literal->offset
*/
uint32_t
bc_find_lit_offset (lit_cpointer_t lit_cp, /**< literal to find */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num) /**< number of entries in the map */
{
uint32_t lit_index;
for (lit_index = 0; lit_index < literals_num; lit_index++)
{
if (lit_map_p[lit_index].literal_id.packed_value == lit_cp.packed_value)
{
break;
}
}
JERRY_ASSERT (lit_index < literals_num);
return lit_map_p[lit_index].literal_offset;
} /* bc_find_lit_offset */
/**
* Write alignment bytes to outptut buffer to align 'in_out_size' to MEM_ALIGNEMENT
*
* @return true if alignment bytes were written successfully
* else otherwise
*/
bool
bc_align_data_in_output_buffer (uint32_t *in_out_size, /**< in: unaligned size, out: aligned size */
uint8_t *buffer_p, /**< buffer where to write */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p) /**< current offset in buffer */
{
uint32_t aligned_size = JERRY_ALIGNUP (*in_out_size, MEM_ALIGNMENT);
if (aligned_size != (*in_out_size))
{
JERRY_ASSERT (aligned_size > (*in_out_size));
uint32_t padding_bytes_num = (uint32_t) (aligned_size - (*in_out_size));
uint8_t padding = 0;
for (uint32_t i = 0; i < padding_bytes_num; i++)
{
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &padding, sizeof (padding)))
{
return false;
}
}
*in_out_size = aligned_size;
}
return true;
} /* bc_align_data_in_output_buffer */
/**
* Dump byte-code and idx-to-literal map of a single scope to snapshot
*
* @return true, upon success (i.e. buffer size is enough),
* false - otherwise.
*/
static bool
bc_save_bytecode_with_idx_map (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
const bytecode_data_header_t *bytecode_data_p, /**< byte-code data */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num) /**< literals number */
{
JERRY_ASSERT (JERRY_ALIGNUP (*in_out_buffer_offset_p, MEM_ALIGNMENT) == *in_out_buffer_offset_p);
jerry_snapshot_bytecode_header_t bytecode_header;
bytecode_header.func_scopes_count = bytecode_data_p->func_scopes_count;
bytecode_header.var_decls_count = bytecode_data_p->var_decls_count;
bytecode_header.is_strict = bytecode_data_p->is_strict;
bytecode_header.is_ref_arguments_identifier = bytecode_data_p->is_ref_arguments_identifier;
bytecode_header.is_ref_eval_identifier = bytecode_data_p->is_ref_eval_identifier;
bytecode_header.is_args_moved_to_regs = bytecode_data_p->is_args_moved_to_regs;
bytecode_header.is_no_lex_env = bytecode_data_p->is_no_lex_env;
size_t bytecode_header_offset = *in_out_buffer_offset_p;
/* Dump instructions */
*in_out_buffer_offset_p += JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT);
vm_instr_counter_t instrs_num = bytecode_data_p->instrs_count;
const size_t instrs_array_size = sizeof (vm_instr_t) * instrs_num;
if (*in_out_buffer_offset_p + instrs_array_size > buffer_size)
{
return false;
}
memcpy (buffer_p + *in_out_buffer_offset_p, bytecode_data_p->instrs_p, instrs_array_size);
*in_out_buffer_offset_p += instrs_array_size;
bytecode_header.instrs_size = (uint32_t) (sizeof (vm_instr_t) * instrs_num);
/* Dump variable declarations */
mem_cpointer_t *func_scopes_p = MEM_CP_GET_POINTER (mem_cpointer_t, bytecode_data_p->declarations_cp);
lit_cpointer_t *var_decls_p = (lit_cpointer_t *) (func_scopes_p + bytecode_data_p->func_scopes_count);
uint32_t null_var_decls_num = 0;
for (uint32_t i = 0; i < bytecode_header.var_decls_count; ++i)
{
lit_cpointer_t lit_cp = var_decls_p[i];
if (lit_cp.packed_value == MEM_CP_NULL)
{
null_var_decls_num++;
continue;
}
uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num);
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset)))
{
return false;
}
}
bytecode_header.var_decls_count -= null_var_decls_num;
/* Dump uid->lit_cp hash table */
lit_id_hash_table *lit_id_hash_p = MEM_CP_GET_POINTER (lit_id_hash_table, bytecode_data_p->lit_id_hash_cp);
uint32_t idx_to_lit_map_size = lit_id_hash_table_dump_for_snapshot (buffer_p,
buffer_size,
in_out_buffer_offset_p,
lit_id_hash_p,
lit_map_p,
literals_num,
instrs_num);
if (idx_to_lit_map_size == 0)
{
return false;
}
bytecode_header.idx_to_lit_map_size = idx_to_lit_map_size;
/* Align to write next bytecode data at aligned address */
bytecode_header.size = (uint32_t) (*in_out_buffer_offset_p - bytecode_header_offset);
JERRY_ASSERT (bytecode_header.size == JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT)
+ bytecode_header.instrs_size
+ bytecode_header.var_decls_count * sizeof (uint32_t)
+ idx_to_lit_map_size);
if (!bc_align_data_in_output_buffer (&bytecode_header.size,
buffer_p,
buffer_size,
in_out_buffer_offset_p))
{
return false;
}
/* Dump header at the saved offset */
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&bytecode_header_offset,
&bytecode_header,
sizeof (bytecode_header)))
{
return false;
}
return true;
} /* bc_save_bytecode_with_idx_map */
/**
* Dump bytecode and summplementary data of all existing scopes to snapshot
*
* @return true if snapshot was dumped successfully
* false otherwise
*/
bool
bc_save_bytecode_data (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
const bytecode_data_header_t *bytecode_data_p, /**< byte-code data */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num, /**< literals number */
uint32_t *out_scopes_num) /**< number of scopes written */
{
bytecode_data_header_t *next_to_handle_list_p = first_bytecode_header_p;
while (next_to_handle_list_p != NULL)
{
if (next_to_handle_list_p == bytecode_data_p)
{
break;
}
next_to_handle_list_p = MEM_CP_GET_POINTER (bytecode_data_header_t, next_to_handle_list_p->next_header_cp);
}
JERRY_ASSERT (next_to_handle_list_p);
JERRY_ASSERT (next_to_handle_list_p->next_header_cp == MEM_CP_NULL);
*out_scopes_num = 0;
while (next_to_handle_list_p!= NULL)
{
bytecode_data_header_t *bc_header_list_iter_p = next_to_handle_list_p;
next_to_handle_list_p = NULL;
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, bc_header_list_iter_p->declarations_cp);
if (!bc_save_bytecode_with_idx_map (buffer_p,
buffer_size,
in_out_buffer_offset_p,
bc_header_list_iter_p,
lit_map_p,
literals_num))
{
return false;
}
(*out_scopes_num)++;
next_to_handle_list_p = MEM_CP_GET_POINTER (bytecode_data_header_t, bc_header_list_iter_p->next_header_cp);
for (uint32_t index = bc_header_list_iter_p->func_scopes_count; index > 0 ; index--)
{
bytecode_data_header_t *child_scope_header_p = MEM_CP_GET_NON_NULL_POINTER (bytecode_data_header_t,
declarations_p[index-1]);
JERRY_ASSERT (child_scope_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (child_scope_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = child_scope_header_p;
}
bc_header_list_iter_p->next_header_cp = MEM_CP_NULL;
}
return true;
} /* bc_save_bytecode_data */
/**
* Register bytecode and supplementary data of a single scope from snapshot
*
* NOTE:
* If is_copy flag is set, bytecode is copied from snapshot, else bytecode is referenced directly
* from snapshot
*
* @return pointer to byte-code header, upon success,
* NULL - upon failure (i.e., in case snapshot format is not valid)
*/
static bytecode_data_header_t *
bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with instructions array
* and idx to literals map from
* snapshot */
size_t snapshot_size, /**< remaining size of snapshot */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals */
bool is_copy, /** flag, indicating whether the passed in-snapshot data
* should be copied to engine's memory (true),
* or it can be referenced until engine is stopped
* (i.e. until call to jerry_cleanup) */
uint32_t *out_bytecode_data_size) /**< out: size occupied by bytecode data
* in snapshot */
{
size_t buffer_offset = 0;
jerry_snapshot_bytecode_header_t bytecode_header;
if (!jrt_read_from_buffer_by_offset (snapshot_data_p,
snapshot_size,
&buffer_offset,
&bytecode_header,
sizeof (bytecode_header)))
{
return NULL;
}
*out_bytecode_data_size = bytecode_header.size;
buffer_offset += (JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT)
- sizeof (jerry_snapshot_bytecode_header_t));
JERRY_ASSERT (bytecode_header.size <= snapshot_size);
/* Read uid->lit_cp hash table size */
const uint8_t *idx_to_lit_map_p = (snapshot_data_p
+ buffer_offset +
+ bytecode_header.instrs_size
+ bytecode_header.var_decls_count * sizeof (uint32_t));
size_t instructions_number = bytecode_header.instrs_size / sizeof (vm_instr_t);
size_t blocks_count = JERRY_ALIGNUP (instructions_number, BLOCK_SIZE) / BLOCK_SIZE;
uint32_t idx_num_total;
size_t idx_to_lit_map_offset = 0;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
bytecode_header.idx_to_lit_map_size,
&idx_to_lit_map_offset,
&idx_num_total,
sizeof (idx_num_total)))
{
return NULL;
}
/* Alloc bytecode_header for runtime */
const size_t bytecode_alloc_size = JERRY_ALIGNUP (bytecode_header.instrs_size, MEM_ALIGNMENT);
const size_t hash_table_size = lit_id_hash_table_get_size_for_table (idx_num_total, blocks_count);
const size_t declarations_area_size = JERRY_ALIGNUP (bytecode_header.func_scopes_count * sizeof (mem_cpointer_t)
+ bytecode_header.var_decls_count * sizeof (lit_cpointer_t),
MEM_ALIGNMENT);
const size_t header_and_tables_size = JERRY_ALIGNUP ((sizeof (bytecode_data_header_t)
+ hash_table_size
+ declarations_area_size),
MEM_ALIGNMENT);
const size_t alloc_size = header_and_tables_size + (is_copy ? bytecode_alloc_size : 0);
uint8_t *buffer_p = (uint8_t*) mem_heap_alloc_block (alloc_size, MEM_HEAP_ALLOC_LONG_TERM);
bytecode_data_header_t *header_p = (bytecode_data_header_t *) buffer_p;
vm_instr_t *instrs_p;
vm_instr_t *snapshot_instrs_p = (vm_instr_t *) (snapshot_data_p + buffer_offset);
if (is_copy)
{
instrs_p = (vm_instr_t *) (buffer_p + header_and_tables_size);
memcpy (instrs_p, snapshot_instrs_p, bytecode_header.instrs_size);
}
else
{
instrs_p = snapshot_instrs_p;
}
buffer_offset += bytecode_header.instrs_size; /* buffer_offset is now offset of variable declarations */
/* Read uid->lit_cp hash table */
uint8_t *lit_id_hash_table_buffer_p = buffer_p + sizeof (bytecode_data_header_t);
if (!(lit_id_hash_table_load_from_snapshot (blocks_count,
idx_num_total,
idx_to_lit_map_p + idx_to_lit_map_offset,
bytecode_header.idx_to_lit_map_size - idx_to_lit_map_offset,
lit_map_p,
literals_num,
lit_id_hash_table_buffer_p,
hash_table_size)
&& (vm_instr_counter_t) instructions_number == instructions_number))
{
mem_heap_free_block (buffer_p);
return NULL;
}
/* Fill with NULLs child scopes declarations for this scope */
mem_cpointer_t *declarations_p = (mem_cpointer_t *) (buffer_p + sizeof (bytecode_data_header_t) + hash_table_size);
memset (declarations_p, 0, bytecode_header.func_scopes_count * sizeof (mem_cpointer_t));
/* Read variable declarations for this scope */
lit_cpointer_t *var_decls_p = (lit_cpointer_t *) (declarations_p + bytecode_header.func_scopes_count);
for (uint32_t i = 0; i < bytecode_header.var_decls_count; i++)
{
uint32_t lit_offset_from_snapshot;
if (!jrt_read_from_buffer_by_offset (snapshot_data_p,
buffer_offset + bytecode_header.var_decls_count * sizeof (uint32_t),
&buffer_offset,
&lit_offset_from_snapshot,
sizeof (lit_offset_from_snapshot)))
{
mem_heap_free_block (buffer_p);
return NULL;
}
/**
* TODO: implement binary search here
*/
lit_cpointer_t lit_cp = NOT_A_LITERAL;
uint32_t j;
for (j = 0; j < literals_num; j++)
{
if (lit_map_p[j].literal_offset == lit_offset_from_snapshot)
{
lit_cp.packed_value = lit_map_p[j].literal_id.packed_value;
break;
}
}
if (j == literals_num)
{
mem_heap_free_block (buffer_p);
return NULL;
}
var_decls_p[i] = lit_cp;
}
/* Fill bytecode_data_header */
bc_fill_bytecode_data_header (header_p,
(lit_id_hash_table *) lit_id_hash_table_buffer_p,
instrs_p,
declarations_p,
(uint16_t) bytecode_header.func_scopes_count,
(uint16_t) bytecode_header.var_decls_count,
bytecode_header.is_strict,
bytecode_header.is_ref_arguments_identifier,
bytecode_header.is_ref_eval_identifier,
bytecode_header.is_args_moved_to_regs,
bytecode_header.is_args_moved_to_regs,
bytecode_header.is_no_lex_env);
return header_p;
} /* bc_load_bytecode_with_idx_map */
/**
* Register bytecode and supplementary data of all scopes from snapshot
*
* NOTE:
* If is_copy flag is set, bytecode is copied from snapshot, else bytecode is referenced directly
* from snapshot
*
* @return pointer to byte-code header, upon success,
* NULL - upon failure (i.e., in case snapshot format is not valid)
*/
const bytecode_data_header_t *
bc_load_bytecode_data (const uint8_t *snapshot_data_p, /**< buffer with instructions array
* and idx to literals map from
* snapshot */
size_t snapshot_size, /**< remaining size of snapshot */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals */
bool is_copy, /** flag, indicating whether the passed in-snapshot data
* should be copied to engine's memory (true),
* or it can be referenced until engine is stopped
* (i.e. until call to jerry_cleanup) */
uint32_t expected_scopes_num) /**< scopes number read from snapshot header */
{
uint32_t snapshot_offset = 0;
uint32_t out_bytecode_data_size = 0;
uint32_t scopes_num = 0;
bytecode_data_header_t *bc_header_p = bc_load_bytecode_with_idx_map (snapshot_data_p,
snapshot_size,
lit_map_p,
literals_num,
is_copy,
&out_bytecode_data_size);
scopes_num++;
snapshot_offset += out_bytecode_data_size;
JERRY_ASSERT (snapshot_offset <= snapshot_size);
bytecode_data_header_t* next_to_handle_list_p = bc_header_p;
while (next_to_handle_list_p != NULL)
{
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, next_to_handle_list_p->declarations_cp);
uint32_t child_scope_index = 0;
while (child_scope_index < next_to_handle_list_p->func_scopes_count
&& declarations_p[child_scope_index] != MEM_CP_NULL)
{
child_scope_index++;
}
if (child_scope_index == next_to_handle_list_p->func_scopes_count)
{
bytecode_data_header_t *bc_header_list_iter_p = MEM_CP_GET_POINTER (bytecode_data_header_t,
next_to_handle_list_p->next_header_cp);
next_to_handle_list_p->next_header_cp = MEM_CP_NULL;
next_to_handle_list_p = bc_header_list_iter_p;
if (next_to_handle_list_p == NULL)
{
break;
}
else
{
continue;
}
}
JERRY_ASSERT (snapshot_offset < snapshot_size);
bytecode_data_header_t *next_header_p = bc_load_bytecode_with_idx_map (snapshot_data_p + snapshot_offset,
snapshot_size - snapshot_offset,
lit_map_p,
literals_num,
is_copy,
&out_bytecode_data_size);
scopes_num++;
snapshot_offset += out_bytecode_data_size;
JERRY_ASSERT (snapshot_offset <= snapshot_size);
MEM_CP_SET_NON_NULL_POINTER (declarations_p[child_scope_index], next_header_p);
if (next_header_p->func_scopes_count > 0)
{
JERRY_ASSERT (next_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (next_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = next_header_p;
}
}
if (expected_scopes_num != scopes_num)
{
return NULL;
}
MEM_CP_SET_POINTER (bc_header_p->next_header_cp, first_bytecode_header_p);
first_bytecode_header_p = bc_header_p;
return bc_header_p;
} /* bc_load_bytecode_data */
#endif /* JERRY_ENABLE_SNAPSHOT */
-109
View File
@@ -1,109 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef BYTECODE_DATA_H
#define BYTECODE_DATA_H
#include "opcodes.h"
#include "mem-allocator.h"
#include "lit-id-hash-table.h"
#include "scopes-tree.h"
/*
* All literals are kept in the 'literals' array.
* Literal structure doesn't hold real string. All program-specific strings
* are kept in the 'strings_buffer' and literal has pointer to this buffer.
*
* Literal id is its index in 'literals' array of bytecode_data_t structure.
*
* Bytecode, which is kept in the 'instrs' field, is divided into blocks
* of 'BLOCK_SIZE' operands. Every block has its own numbering of literals.
* Literal uid could be in range [0, 127] in every block.
*
* To map uid to literal id 'lit_id_hash' table is used.
*/
#define BLOCK_SIZE 32u
/**
* Header of byte-code memory region, containing byte-code array and literal identifiers hash table
*/
typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) bytecode_data_header_t
{
vm_instr_t *instrs_p; /**< pointer to the bytecode */
vm_instr_counter_t instrs_count; /**< number of instructions in the byte-code array */
mem_cpointer_t lit_id_hash_cp; /**< pointer to literal identifiers hash table
* See also: lit_id_hash_table_init */
mem_cpointer_t declarations_cp; /**< function scopes and variable declarations inside current scope */
uint16_t func_scopes_count; /**< count of function scopes inside current scope */
uint16_t var_decls_count; /**< count of variable declrations inside current scope */
mem_cpointer_t next_header_cp; /**< pointer to next instructions data header */
uint8_t is_strict : 1; /**< code is strict mode code */
uint8_t is_ref_arguments_identifier : 1; /**< code doesn't reference 'arguments' identifier */
uint8_t is_ref_eval_identifier : 1; /**< code doesn't reference 'eval' identifier */
uint8_t is_vars_and_args_to_regs_possible : 1; /**< flag, indicating whether it is possible
* to safely perform var-to-reg
* optimization on the scope
*
* TODO: remove the flag when var-to-reg optimization
* would be moved from post-parse to dump stage */
uint8_t is_args_moved_to_regs : 1; /**< the function's arguments are moved to registers,
* so should be initialized in vm registers,
* and not in lexical environment */
uint8_t is_no_lex_env : 1; /**< no lex. env. is necessary for the scope */
} bytecode_data_header_t;
JERRY_STATIC_ASSERT (sizeof (bytecode_data_header_t) % MEM_ALIGNMENT == 0);
void bc_remove_bytecode_data (const bytecode_data_header_t *);
vm_instr_t bc_get_instr (const bytecode_data_header_t *,
vm_instr_counter_t);
void bc_print_instrs (const bytecode_data_header_t *);
bytecode_data_header_t *bc_dump_single_scope (scopes_tree);
void bc_register_root_bytecode_header (bytecode_data_header_t *);
void bc_finalize ();
lit_cpointer_t
bc_get_literal_cp_by_uid (uint8_t,
const bytecode_data_header_t *,
vm_instr_counter_t);
#ifdef JERRY_ENABLE_SNAPSHOT
/*
* Snapshot-related
*/
uint32_t
bc_find_lit_offset (lit_cpointer_t, const lit_mem_to_snapshot_id_map_entry_t *, uint32_t);
bool
bc_align_data_in_output_buffer (uint32_t *, uint8_t *, size_t, size_t *);
bool
bc_save_bytecode_data (uint8_t *, size_t, size_t *, const bytecode_data_header_t *,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, uint32_t *);
const bytecode_data_header_t *
bc_load_bytecode_data (const uint8_t *, size_t,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, bool, uint32_t);
#endif /* JERRY_ENABLE_SNAPSHOT */
#endif /* BYTECODE_DATA_H */
+78
View File
@@ -0,0 +1,78 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_bytecode Bytecode
* @{
*/
#define CBC_OPCODE(arg1, arg2, arg3, arg4) \
((arg2) | (((arg3) + CBC_STACK_ADJUST_BASE) << CBC_STACK_ADJUST_SHIFT)),
/**
* Flags of the opcodes.
*/
const uint8_t cbc_flags[] =
{
CBC_OPCODE_LIST
};
/**
* Flags of the extended opcodes.
*/
const uint8_t cbc_ext_flags[] =
{
CBC_EXT_OPCODE_LIST
};
#undef CBC_OPCODE
#ifdef PARSER_DUMP_BYTE_CODE
#define CBC_OPCODE(arg1, arg2, arg3, arg4) #arg1,
/**
* Names of the opcodes.
*/
const char *cbc_names[] =
{
CBC_OPCODE_LIST
};
/**
* Names of the extended opcodes.
*/
const char *cbc_ext_names[] =
{
CBC_EXT_OPCODE_LIST
};
#undef CBC_OPCODE
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
+694
View File
@@ -0,0 +1,694 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef BYTE_CODE_H
#define BYTE_CODE_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_bytecode Bytecode
* @{
*/
/**
* Compact byte code (CBC) is a byte code representation
* of EcmaScript which is designed for low memory
* environments. Most opcodes are only one or sometimes
* two byte long so the CBC provides a small binary size.
*
* The execution engine of CBC is a stack machine, where
* the maximum stack size is known in advance for each
* function.
*/
/**
* Byte code flags. Only the lower 5 bit can be used
* since the stack change is encoded in the upper
* three bits for each instruction between -4 and 3
* (except for call / construct opcodes).
*/
#define CBC_STACK_ADJUST_BASE 4
#define CBC_STACK_ADJUST_SHIFT 5
#define CBC_STACK_ADJUST_VALUE(value) \
(((value) >> CBC_STACK_ADJUST_SHIFT) - CBC_STACK_ADJUST_BASE)
#define CBC_NO_FLAG 0x00u
#define CBC_HAS_LITERAL_ARG 0x01u
#define CBC_HAS_LITERAL_ARG2 0x02u
#define CBC_HAS_BYTE_ARG 0x04u
#define CBC_HAS_BRANCH_ARG 0x08u
/* These flags are shared */
#define CBC_FORWARD_BRANCH_ARG 0x10u
#define CBC_POP_STACK_BYTE_ARG 0x10u
#define CBC_ARG_TYPES (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2 | CBC_HAS_BYTE_ARG | CBC_HAS_BRANCH_ARG)
#define CBC_HAS_POP_STACK_BYTE_ARG (CBC_HAS_BYTE_ARG | CBC_POP_STACK_BYTE_ARG)
/* Debug macro. */
#define CBC_ARGS_EQ(op, types) \
((cbc_flags[op] & CBC_ARG_TYPES) == (types))
/* Debug macro. */
#define CBC_SAME_ARGS(op1, op2) \
((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))
#define CBC_UNARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, 0, \
(VM_OC_ ## group) | VM_OC_GET_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _LITERAL, CBC_HAS_LITERAL_ARG, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_STACK)
#define CBC_BINARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -1, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _RIGHT_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK)
#define CBC_UNARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -2, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (name ## _PUSH_RESULT, CBC_NO_FLAG, -1, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _BLOCK, CBC_NO_FLAG, -2, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (name ## _IDENT, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (name ## _IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _IDENT_BLOCK, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK)
#define CBC_BINARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -4, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (name ## _LITERAL, CBC_HAS_LITERAL_ARG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE) \
#define CBC_EXT_BINARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name ## _PUSH_RESULT, CBC_NO_FLAG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, -2, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
#define CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION(name, group) \
CBC_OPCODE (name ## _BLOCK, CBC_NO_FLAG, -4, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (name ## _LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
#define CBC_UNARY_LVALUE_WITH_IDENT 3
#define CBC_BINARY_LVALUE_WITH_LITERAL 1
#define CBC_BINARY_WITH_LITERAL 1
#define CBC_BINARY_WITH_TWO_LITERALS 2
/**
* Several opcodes (mostly call and assignment opcodes) have
* two forms: one which does not push a return value onto
* the stack, and another which does. The reasion is that
* the return value of these opcodes are often not used
* and the first form provides smaller byte code.
*
* The following rules must be kept by the code generator:
* - only the opcode without return value can be emitted
* by the code generator
* - the first form can be converted to the second form
* by adding 1 to the opcode
* - after the conversion the opcode must be immediately
* flushed, so no further changes are possible
*
* Hence CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)
* cannot be true for an opcode which has a result
*/
#define CBC_NO_RESULT_OPERATION(opcode) \
((opcode) >= CBC_DELETE && (opcode) < CBC_END)
#define CBC_NO_RESULT_BLOCK(opcode) \
((opcode) >= CBC_DELETE && (opcode) < CBC_ASSIGN_ADD)
#define CBC_NO_RESULT_COMPOUND_ASSIGMENT(opcode) \
((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END)
/**
* Branch instructions are organized in group of 8 opcodes.
* - 1st opcode: unused, can be used for other purpose
* - 2nd opcode: forward branch with 1 byte offset
* - 3rd opcode: forward branch with 2 byte offset
* - 4th opcode: forward branch with 3 byte offset
* - 5th opcode: unused, can be used for other purpose
* - 6th opcode: backward branch with 1 byte offset
* - 7th opcode: backward branch with 2 byte offset
* - 8th opcode: backward branch with 3 byte offset
*
* Reasons:
* The branch_opcode & 0x3 tells the length in bytes of the offset
* If branch offset & 0x4 == 0, it is a forward branch. Otherwise
* it is backward.
*
* The offset bytes are encoded in higher to lower order.
*/
#define CBC_FORWARD_BRANCH(name, stack, vm_oc) \
CBC_OPCODE (name, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc))
#define CBC_BACKWARD_BRANCH(name, stack, vm_oc) \
CBC_OPCODE (name, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc))
#define CBC_BRANCH_OFFSET_LENGTH(opcode) \
((opcode) & 0x3)
#define CBC_BRANCH_IS_BACKWARD(flags) \
(!((flags) & CBC_FORWARD_BRANCH_ARG))
#define CBC_BRANCH_IS_FORWARD(flags) \
((flags) & CBC_FORWARD_BRANCH_ARG)
/* Stack consumption of opcodes with context. */
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 3
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 2
/* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2
/**
* Opcode definitions.
*/
#define CBC_OPCODE_LIST \
/* Branch opcodes first. Some other opcodes are mixed. */ \
CBC_OPCODE (CBC_EXT_OPCODE, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD, 0, \
VM_OC_JUMP) \
CBC_OPCODE (CBC_POP, CBC_NO_FLAG, -1, \
VM_OC_POP) \
CBC_BACKWARD_BRANCH (CBC_JUMP_BACKWARD, 0, \
VM_OC_JUMP) \
CBC_OPCODE (CBC_POP_BLOCK, CBC_NO_FLAG, -1, \
VM_OC_POP_BLOCK | VM_OC_PUT_BLOCK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_TRUE_FORWARD, -1, \
VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_THROW, CBC_NO_FLAG, -1, \
VM_OC_THROW | VM_OC_GET_STACK) \
CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_TRUE_BACKWARD, -1, \
VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_CONTEXT_END, CBC_NO_FLAG, 0, \
VM_OC_CONTEXT_END) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_FALSE_FORWARD, -1, \
VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_CREATE_OBJECT, CBC_NO_FLAG, 1, \
VM_OC_PUSH_OBJECT | VM_OC_PUT_STACK) \
CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_FALSE_BACKWARD, -1, \
VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_SET_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \
CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD_EXIT_CONTEXT, 0, \
VM_OC_JUMP_AND_EXIT_CONTEXT) \
CBC_OPCODE (CBC_CREATE_ARRAY, CBC_NO_FLAG, 1, \
VM_OC_PUSH_ARRAY | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_TRUE, -1, \
VM_OC_BRANCH_IF_LOGICAL_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_APPEND_ARRAY | VM_OC_GET_BYTE) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_FALSE, -1, \
VM_OC_BRANCH_IF_LOGICAL_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_PUSH_ELISION, CBC_NO_FLAG, 1, \
VM_OC_PUSH_ELISON | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_STRICT_EQUAL, -1, \
VM_OC_BRANCH_IF_STRICT_EQUAL | VM_OC_GET_STACK) \
\
/* Basic opcodes. */ \
CBC_OPCODE (CBC_PUSH_LITERAL, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_PUSH | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_PUSH_TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_PUSH_THREE_LITERALS, CBC_HAS_LITERAL_ARG2, 3, \
VM_OC_PUSH_THREE | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_PUSH_UNDEFINED, CBC_NO_FLAG, 1, \
VM_OC_PUSH_UNDEFINED | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_TRUE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_TRUE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_FALSE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_FALSE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_THIS, CBC_NO_FLAG, 1, \
VM_OC_PUSH_THIS | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_THIS_LITERAL) \
CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NUMBER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_1, CBC_HAS_BYTE_ARG, 1, \
VM_OC_PUSH_NUMBER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP, CBC_NO_FLAG, -1, \
VM_OC_PROP_GET | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_PROP_GET | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
VM_OC_PROP_GET | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_PROP_GET | VM_OC_GET_THIS_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_IDENT_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \
VM_OC_IDENT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_REFERENCE, CBC_NO_FLAG, 1, \
VM_OC_PROP_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PROP_REFERENCE | VM_OC_GET_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 3, \
VM_OC_PROP_REFERENCE | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_THIS_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \
VM_OC_PROP_REFERENCE | VM_OC_GET_THIS_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_NEW | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW0, CBC_NO_FLAG, 0, \
VM_OC_NEW_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW1, CBC_NO_FLAG, -1, \
VM_OC_NEW_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \
VM_OC_EVAL) \
CBC_OPCODE (CBC_DEFINE_VARS, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_INITIALIZE_VAR, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_INITIALIZE_VARS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_RETURN, CBC_NO_FLAG, -1, \
VM_OC_RET | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_RETURN_WITH_BLOCK, CBC_NO_FLAG, 0, \
VM_OC_RET) \
CBC_OPCODE (CBC_RETURN_WITH_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_RET | VM_OC_GET_LITERAL) \
\
/* Unary opcodes. */ \
CBC_UNARY_OPERATION (CBC_PLUS, \
PLUS) \
CBC_UNARY_OPERATION (CBC_NEGATE, \
MINUS) \
CBC_UNARY_OPERATION (CBC_LOGICAL_NOT, \
NOT) \
CBC_UNARY_OPERATION (CBC_BIT_NOT, \
BIT_NOT) \
CBC_UNARY_OPERATION (CBC_VOID, \
VOID) \
CBC_OPCODE (CBC_TYPEOF, CBC_NO_FLAG, 0, \
VM_OC_TYPEOF | VM_OC_GET_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_TYPEOF_IDENT, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_TYPEOF_IDENT | VM_OC_PUT_STACK) \
\
/* Binary opcodes. */ \
CBC_BINARY_OPERATION (CBC_BIT_OR, \
BIT_OR) \
CBC_BINARY_OPERATION (CBC_BIT_XOR, \
BIT_XOR) \
CBC_BINARY_OPERATION (CBC_BIT_AND, \
BIT_AND) \
CBC_BINARY_OPERATION (CBC_EQUAL, \
EQUAL) \
CBC_BINARY_OPERATION (CBC_NOT_EQUAL, \
NOT_EQUAL) \
CBC_BINARY_OPERATION (CBC_STRICT_EQUAL, \
STRICT_EQUAL) \
CBC_BINARY_OPERATION (CBC_STRICT_NOT_EQUAL, \
STRICT_NOT_EQUAL) \
CBC_BINARY_OPERATION (CBC_LESS, \
LESS) \
CBC_BINARY_OPERATION (CBC_GREATER, \
GREATER) \
CBC_BINARY_OPERATION (CBC_LESS_EQUAL, \
LESS_EQUAL) \
CBC_BINARY_OPERATION (CBC_GREATER_EQUAL, \
GREATER_EQUAL) \
CBC_BINARY_OPERATION (CBC_IN, \
IN) \
CBC_BINARY_OPERATION (CBC_INSTANCEOF, \
INSTANCEOF) \
CBC_BINARY_OPERATION (CBC_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_BINARY_OPERATION (CBC_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_BINARY_OPERATION (CBC_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_BINARY_OPERATION (CBC_ADD, \
ADD) \
CBC_BINARY_OPERATION (CBC_SUBTRACT, \
SUB) \
CBC_BINARY_OPERATION (CBC_MULTIPLY, \
MUL) \
CBC_BINARY_OPERATION (CBC_DIVIDE, \
DIV) \
CBC_BINARY_OPERATION (CBC_MODULO, \
MOD) \
\
/* Unary lvalue opcodes. */ \
CBC_OPCODE (CBC_DELETE, CBC_NO_FLAG, -2, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_DELETE_PUSH_RESULT, CBC_NO_FLAG, -1, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_DELETE_BLOCK, CBC_NO_FLAG, -2, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_DELETE_IDENT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_DELETE) \
CBC_OPCODE (CBC_DELETE_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_DELETE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_DELETE_IDENT_BLOCK, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_DELETE | VM_OC_PUT_BLOCK) \
CBC_UNARY_LVALUE_OPERATION (CBC_PRE_INCR, \
PRE_INCR) \
CBC_UNARY_LVALUE_OPERATION (CBC_PRE_DECR, \
PRE_DECR) \
CBC_UNARY_LVALUE_OPERATION (CBC_POST_INCR, \
POST_INCR) \
CBC_UNARY_LVALUE_OPERATION (CBC_POST_DECR, \
POST_DECR) \
\
/* Call opcodes. */ \
CBC_OPCODE (CBC_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_CALL | VM_OC_GET_BYTE) \
CBC_OPCODE (CBC_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL_PROP, CBC_HAS_POP_STACK_BYTE_ARG, -3, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE) \
CBC_OPCODE (CBC_CALL_PROP_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, -2, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL_PROP_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -3, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL0, CBC_NO_FLAG, -1, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL0_PUSH_RESULT, CBC_NO_FLAG, 0, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL0_BLOCK, CBC_NO_FLAG, -1, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL0_PROP, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL0_PROP_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL0_PROP_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL1, CBC_NO_FLAG, -2, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL1_PUSH_RESULT, CBC_NO_FLAG, -1, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL1_BLOCK, CBC_NO_FLAG, -2, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL1_PROP, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL1_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL1_PROP_BLOCK, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL2, CBC_NO_FLAG, -3, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL2_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL2_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL2_PROP, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL2_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL2_PROP_BLOCK, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
\
/* Binary assignment opcodes. */ \
CBC_OPCODE (CBC_ASSIGN, CBC_NO_FLAG, -3, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT_BLOCK, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT_BLOCK, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL, CBC_HAS_LITERAL_ARG, -2, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -2, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
\
/* Binary compound assignment opcodes. */ \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_ADD, \
ADD) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_SUBTRACT, \
SUB) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_MULTIPLY, \
MUL) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_DIVIDE, \
DIV) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_MODULO, \
MOD) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Last opcode (not a real opcode). */ \
CBC_OPCODE (CBC_END, CBC_NO_FLAG, 0, \
VM_OC_NONE)
/* All EXT branches are statement block end
* marks, so they are always forward branches. */
#define CBC_EXT_OPCODE_LIST \
/* Branch opcodes first. Some other opcodes are mixed. */ \
CBC_OPCODE (CBC_EXT_NOP, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_FORWARD_BRANCH (CBC_EXT_WITH_CREATE_CONTEXT, \
-1 + PARSER_WITH_CONTEXT_STACK_ALLOCATION, VM_OC_WITH | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_FOR_IN_GET_NEXT, CBC_NO_FLAG, 1, \
VM_OC_FOR_IN_GET_NEXT | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_CREATE_CONTEXT, \
-1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_SET_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_GETTER | VM_OC_GET_LITERAL_LITERAL) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, 0, \
VM_OC_FOR_IN_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_SET_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_SETTER | VM_OC_GET_LITERAL_LITERAL) \
CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \
VM_OC_TRY) \
CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \
VM_OC_THROW_REFERENCE_ERROR) \
CBC_FORWARD_BRANCH (CBC_EXT_CATCH, 1, \
VM_OC_CATCH) \
CBC_OPCODE (CBC_EXT_PUSH_UNDEFINED_BASE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_UNDEFINED_BASE | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \
VM_OC_FINALLY) \
\
/* Basic opcodes. */ \
CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
\
/* Binary compound assignment opcodes with pushing the result. */ \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \
ADD) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_SUBTRACT, \
SUB) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_MULTIPLY, \
MUL) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_DIVIDE, \
DIV) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_MODULO, \
MOD) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Binary compound assignment opcodes with saving the result. */ \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_ADD, \
ADD) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_SUBTRACT, \
SUB) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_MULTIPLY, \
MUL) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_DIVIDE, \
DIV) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_MODULO, \
MOD) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Last opcode (not a real opcode). */ \
CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \
VM_OC_NONE)
#define CBC_MAXIMUM_BYTE_VALUE 255
#define CBC_MAXIMUM_SMALL_VALUE 510
#define CBC_MAXIMUM_FULL_VALUE 32767
#define CBC_PUSH_NUMBER_1_RANGE_END 128
#define CBC_HIGHEST_BIT_MASK 0x80
#define CBC_LOWER_SEVEN_BIT_MASK 0x7f
/**
* Literal indicies belong to one of the following groups:
*
* 0 <= index < argument_end : arguments
* argument_end <= index < register_end : registers
* register_end <= index < ident_end : identifiers
* ident_end <= index < const_literal_end : constant literals
* const_literal_end <= index < literal_end : template literals
*/
/**
* Compiled byte code arguments.
*/
typedef struct
{
uint16_t status_flags; /**< various status flags */
uint8_t stack_limit; /**< maximum number of values stored on the stack */
uint8_t argument_end; /**< number of arguments expected by the function */
uint8_t register_end; /**< end position of the register group */
uint8_t ident_end; /**< end position of the identifier group */
uint8_t const_literal_end; /**< end position of the const literal group */
uint8_t literal_end; /**< end position of the literal group */
} cbc_uint8_arguments_t;
/**
* Compiled byte code arguments.
*/
typedef struct
{
uint16_t status_flags; /**< various status flags */
uint16_t stack_limit; /**< maximum number of values stored on the stack */
uint16_t argument_end; /**< number of arguments expected by the function */
uint16_t register_end; /**< end position of the register group */
uint16_t ident_end; /**< end position of the identifier group */
uint16_t const_literal_end; /**< end position of the const literal group */
uint16_t literal_end; /**< end position of the literal group */
} cbc_uint16_arguments_t;
/* When CBC_CODE_FLAGS_FULL_LITERAL_ENCODING
* is not set the small encoding is used. */
#define CBC_CODE_FLAGS_FUNCTION 0x01
#define CBC_CODE_FLAGS_FULL_LITERAL_ENCODING 0x02
#define CBC_CODE_FLAGS_UINT16_ARGUMENTS 0x04
#define CBC_CODE_FLAGS_STRICT_MODE 0x08
#define CBC_CODE_FLAGS_ARGUMENTS_NEEDED 0x10
#define CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED 0x20
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,
/**
* Opcode list.
*/
typedef enum
{
CBC_OPCODE_LIST /**< list of opcodes */
} cbc_opcode_t;
/**
* Extended opcode list.
*/
typedef enum
{
CBC_EXT_OPCODE_LIST /**< list extended opcodes */
} cbc_ext_opcode_t;
#undef CBC_OPCODE
/**
* Opcode flags.
*/
extern const uint8_t cbc_flags[];
extern const uint8_t cbc_ext_flags[];
#ifdef PARSER_DUMP_BYTE_CODE
/**
* Opcode names for debugging.
*/
extern const char *cbc_names[];
extern const char *cbc_ext_names[];
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
#endif /* !BYTE_CODE_H */
@@ -1,135 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "array-list.h"
#include "jrt-libc-includes.h"
#include "jsp-mm.h"
typedef struct
{
uint8_t element_size;
size_t len;
size_t size;
} array_list_header;
static array_list_header *
extract_header (array_list al)
{
JERRY_ASSERT (al != null_list);
array_list_header *header = (array_list_header *) al;
return header;
}
static uint8_t *
data (array_list al)
{
return (uint8_t *) al + sizeof (array_list_header);
}
array_list
array_list_append (array_list al, void *element)
{
array_list_header *h = extract_header (al);
if ((h->len + 1) * h->element_size + sizeof (array_list_header) > h->size)
{
size_t size = jsp_mm_recommend_size (h->size + h->element_size);
JERRY_ASSERT (size > h->size);
uint8_t *new_block_p = (uint8_t *) jsp_mm_alloc (size);
memcpy (new_block_p, h, h->size);
memset (new_block_p + h->size, 0, size - h->size);
jsp_mm_free (h);
h = (array_list_header *) new_block_p;
h->size = size;
al = (array_list) h;
}
memcpy (data (al) + (h->len * h->element_size), element, h->element_size);
h->len++;
return al;
}
void
array_list_drop_last (array_list al)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (h->len > 0);
h->len--;
}
void *
array_list_element (array_list al, size_t index)
{
array_list_header *h = extract_header (al);
if (h->len <= index)
{
return NULL;
}
return data (al) + (index * h->element_size);
}
void
array_list_set_element (array_list al, size_t index, void *elem)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (index < h->len);
memcpy (data (al) + (index * h->element_size), elem, h->element_size);
}
void *
array_list_last_element (array_list al, size_t index)
{
array_list_header *h = extract_header (al);
if (index == 0 || index > h->len)
{
return NULL;
}
return array_list_element (al, (size_t) (h->len - index));
}
void
array_list_set_last_element (array_list al, size_t index, void *elem)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (index != 0 && index <= h->len);
array_list_set_element (al, (size_t) (h->len - index), elem);
}
array_list
array_list_init (uint8_t element_size)
{
size_t size = jsp_mm_recommend_size (sizeof (array_list_header));
array_list_header *header = (array_list_header *) jsp_mm_alloc (size);
memset (header, 0, size);
header->element_size = element_size;
header->len = 0;
header->size = size;
return (array_list) header;
}
size_t
array_list_len (array_list al)
{
array_list_header *h = extract_header (al);
return h->len;
}
void
array_list_free (array_list al)
{
array_list_header *h = extract_header (al);
jsp_mm_free (h);
}
@@ -1,34 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef ARRAY_LIST_H
#define ARRAY_LIST_H
#include "jrt.h"
typedef uint8_t *array_list;
#define null_list NULL
array_list array_list_init (uint8_t);
void array_list_free (array_list);
array_list array_list_append (array_list, void *);
void array_list_drop_last (array_list);
void *array_list_element (array_list, size_t);
void array_list_set_element (array_list, size_t, void *);
void *array_list_last_element (array_list, size_t);
void array_list_set_last_element (array_list, size_t, void *);
size_t array_list_len (array_list);
#endif /* ARRAY_LIST_H */
@@ -1,334 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "jrt-libc-includes.h"
#include "jsp-mm.h"
#include "linked-list.h"
/**
* Header of a linked list's chunk
*/
typedef struct linked_list_chunk_header
{
struct linked_list_chunk_header *next_p; /**< pointer to next chunk of the list */
} linked_list_chunk_header;
/**
* Header of a linked list
*/
typedef struct
{
uint16_t list_length; /**< number of elements */
uint16_t element_size; /**< size of an element */
} linked_list_header;
#define ASSERT_LIST(list) \
do { \
linked_list_header *header = (linked_list_header *) list; \
JERRY_ASSERT (header); \
} while (0);
/**
* Calculate size of a linked list's chunk
*
* @return size of the chunk's data space
*/
static size_t
linked_list_block_size (bool is_first_chunk) /**< is it first chunk (chunk, containing header)? */
{
if (is_first_chunk)
{
return (jsp_mm_recommend_size (sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + 1u)
- sizeof (linked_list_header) - sizeof (linked_list_chunk_header));
}
else
{
return (jsp_mm_recommend_size (sizeof (linked_list_chunk_header) + 1u) - sizeof (linked_list_chunk_header));
}
} /* linked_list_block_size */
/**
* Initialize linked list
*
* @return linked list's identifier
*/
linked_list
linked_list_init (size_t element_size) /**< size of a linked list's element */
{
JERRY_ASSERT (element_size <= linked_list_block_size (true));
size_t size = sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + linked_list_block_size (true);
linked_list list = (linked_list) jsp_mm_alloc (size);
JERRY_ASSERT (list != null_list);
linked_list_header *header_p = (linked_list_header *) list;
header_p->element_size = (uint16_t) element_size;
JERRY_ASSERT (header_p->element_size == element_size);
header_p->list_length = 0;
linked_list_chunk_header* chunk_header_p = (linked_list_chunk_header *) (header_p + 1u);
chunk_header_p->next_p = NULL;
return list;
} /* linked_list_init */
/**
* Create and append new chunk to list
*
* @return pointer to the new chunk
*/
static linked_list_chunk_header *
linked_list_append_new_chunk (linked_list_header *header_p, /**< linked list's header */
linked_list_chunk_header *last_chunk_header_p) /**< last chunk of the list */
{
JERRY_ASSERT (header_p != NULL && last_chunk_header_p != NULL);
JERRY_ASSERT (header_p->element_size <= linked_list_block_size (false));
size_t size = sizeof (linked_list_chunk_header) + linked_list_block_size (false);
linked_list_chunk_header *new_chunk_header_p = (linked_list_chunk_header *) jsp_mm_alloc (size);
JERRY_ASSERT (new_chunk_header_p != NULL);
new_chunk_header_p->next_p = NULL;
JERRY_ASSERT (last_chunk_header_p->next_p == NULL);
last_chunk_header_p->next_p = new_chunk_header_p;
return new_chunk_header_p;
} /* linked_list_append_new_chunk */
/**
* Free the linked list
*/
void
linked_list_free (linked_list list) /**< linked list's identifier */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *first_chunk_header_p = (linked_list_chunk_header *) (header_p + 1u);
linked_list_chunk_header *iter_p = first_chunk_header_p->next_p;
while (iter_p != NULL)
{
linked_list_chunk_header *iter_next_p = iter_p->next_p;
jsp_mm_free (iter_p);
iter_p = iter_next_p;
}
jsp_mm_free (header_p);
} /* linked_list_free */
/**
* Get pointer to next element of the list
*
* @return pointer to the next element's area,
* or NULL - in case end of list was reached.
*/
static uint8_t*
linked_list_switch_to_next_elem (linked_list_header *header_p, /**< list header */
linked_list_chunk_header **in_out_chunk_header_p, /**< list iterator (in case end
* of list was reached,
* the iterator points
* to last chunk of the list) */
uint8_t *raw_elem_ptr_p) /**< element to get the next element for */
{
linked_list_chunk_header *chunk_header_p = *in_out_chunk_header_p;
const size_t element_size = header_p->element_size;
const bool is_first_chunk = ((linked_list_chunk_header *) (header_p + 1u) == chunk_header_p);
JERRY_ASSERT (raw_elem_ptr_p + element_size
<= (uint8_t *) (chunk_header_p + 1u) + linked_list_block_size (is_first_chunk));
const size_t elements_in_chunk = linked_list_block_size (is_first_chunk) / element_size;
uint8_t *raw_start_p = (uint8_t *) (chunk_header_p + 1u);
JERRY_ASSERT (raw_elem_ptr_p >= raw_start_p);
size_t element_offset = (size_t) (raw_elem_ptr_p - raw_start_p) / element_size;
if (element_offset == elements_in_chunk - 1)
{
linked_list_chunk_header *next_chunk_header_p = chunk_header_p->next_p;
if (next_chunk_header_p == NULL)
{
return NULL;
}
else
{
*in_out_chunk_header_p = next_chunk_header_p;
return (uint8_t *) (next_chunk_header_p + 1u);
}
}
else
{
JERRY_ASSERT (element_offset < elements_in_chunk - 1u);
return (raw_elem_ptr_p + element_size);
}
} /* linked_list_switch_to_next_elem */
/**
* Get pointer to the linked list's element
*/
void *
linked_list_element (linked_list list, /**< linked list's identifier */
size_t element_num) /**< index of the element */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
if (element_num >= header_p->list_length)
{
return NULL;
}
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1);
for (size_t i = 0; i < element_num; i++)
{
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
if (element_iter_p == NULL)
{
return NULL;
}
}
return element_iter_p;
} /* linked_list_element */
/**
* Set linked list's element
*/
void
linked_list_set_element (linked_list list, /**< linked list's identifier */
size_t element_num, /**< index of element to set */
void *element_p) /**< pointer to new value of the element */
{
if (element_p == NULL)
{
return;
}
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
for (size_t i = 0; i < element_num; i++)
{
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
if (element_iter_p == NULL)
{
JERRY_ASSERT (element_num >= header_p->list_length);
linked_list_append_new_chunk (header_p, list_chunk_iter_p);
list_chunk_iter_p = list_chunk_iter_p->next_p;
element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
}
}
if (element_num + 1 > header_p->list_length)
{
header_p->list_length = (uint16_t) (element_num + 1u);
JERRY_ASSERT (header_p->list_length == element_num + 1u);
}
JERRY_ASSERT (element_iter_p != NULL);
memcpy (element_iter_p, element_p, header_p->element_size);
} /* linked_list_set_element */
/**
* Remove specified element from the linked list
*/
void
linked_list_remove_element (linked_list list, /**< linked list's identifier */
size_t element_num) /**< position of the element */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
linked_list_chunk_header *chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
const size_t list_length = header_p->list_length;
const size_t element_size = header_p->element_size;
JERRY_ASSERT (element_num < list_length);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
for (size_t i = 0; i < element_num; i++)
{
chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
JERRY_ASSERT (element_iter_p != NULL);
}
uint8_t *next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
JERRY_ASSERT ((element_num + 1 == list_length && next_elem_iter_p == NULL)
|| (next_elem_iter_p != NULL));
for (size_t i = element_num + 1; i < list_length; i++)
{
JERRY_ASSERT (next_elem_iter_p != NULL);
memcpy (element_iter_p, next_elem_iter_p, element_size);
chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
element_iter_p = next_elem_iter_p;
next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, next_elem_iter_p);
}
if (list_chunk_iter_p != chunk_prev_to_chunk_with_last_elem_p)
{
JERRY_ASSERT (chunk_prev_to_chunk_with_last_elem_p->next_p == list_chunk_iter_p);
jsp_mm_free (list_chunk_iter_p);
chunk_prev_to_chunk_with_last_elem_p->next_p = NULL;
}
header_p->list_length--;
} /* linked_list_remove_element */
/**
* Get length of the linked list
*
* @return length
*/
uint16_t
linked_list_get_length (linked_list list) /**< linked list's identifier */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
return header_p->list_length;
} /* linked_list_get_length */
@@ -1,31 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
#include "jrt.h"
typedef uint8_t *linked_list;
#define null_list NULL
linked_list linked_list_init (size_t);
void linked_list_free (linked_list);
void *linked_list_element (linked_list, size_t);
void linked_list_set_element (linked_list, size_t, void *);
void linked_list_remove_element (linked_list, size_t);
uint16_t linked_list_get_length (linked_list);
#endif /* LINKED_LIST_H */
@@ -1,355 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "lit-id-hash-table.h"
#include "bytecode-data.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup collections Collections
* @{
*
* \addtogroup lit_id_hash_table Literal identifiers hash table
* The hash table connects pairs (instruction block, vm_idx_t value) with literal identifiers.
* @{
*/
/**
* Initialize literal identifiers hash table
*
* @return pointer to header of the table
*/
lit_id_hash_table *
lit_id_hash_table_init (uint8_t *table_buffer_p, /**< buffer to initialize hash table in */
size_t buffer_size, /**< size of the buffer */
size_t buckets_count, /**< number of pairs */
size_t blocks_count) /**< number of instruction blocks */
{
const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT);
const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT);
const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT);
JERRY_ASSERT (header_size + raw_buckets_size + buckets_size <= buffer_size);
lit_id_hash_table *table_p = (lit_id_hash_table *) table_buffer_p;
table_p->current_bucket_pos = 0;
table_p->raw_buckets = (lit_cpointer_t*) (table_buffer_p + header_size);
table_p->buckets = (lit_cpointer_t **) (table_buffer_p + header_size + raw_buckets_size);
memset (table_p->buckets, 0, buckets_size);
return table_p;
} /* lit_id_hash_table_init */
/**
* Get size of buffer, necessary to hold hash table with specified parameters
*
* @return size of buffer
*/
size_t
lit_id_hash_table_get_size_for_table (size_t buckets_count, /**< number of pairs */
size_t blocks_count) /**< number of instructions blocks */
{
const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT);
const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT);
const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT);
return header_size + raw_buckets_size + buckets_size;
} /* lit_id_hash_table_get_size_for_table */
/**
* Free literal identifiers hash table
*/
void
lit_id_hash_table_free (lit_id_hash_table *table_p) /**< table's header */
{
JERRY_ASSERT (table_p != NULL);
mem_heap_free_block ((uint8_t *) table_p);
} /* lit_id_hash_table_free */
/**
* Register literal in the hash table
*
* @return corresponding idx
*/
vm_idx_t
lit_id_hash_table_insert (lit_id_hash_table *table_p, /**< table's header */
vm_instr_counter_t oc, /**< instruction counter of the instruction */
lit_cpointer_t lit_cp) /**< literal identifier */
{
JERRY_ASSERT (table_p != NULL);
size_t block_id = oc / BLOCK_SIZE;
if (table_p->buckets[block_id] == NULL)
{
table_p->buckets[block_id] = table_p->raw_buckets + table_p->current_bucket_pos;
}
lit_cpointer_t *raw_bucket_iter_p = table_p->raw_buckets + table_p->current_bucket_pos;
JERRY_ASSERT (raw_bucket_iter_p >= table_p->buckets[block_id]);
ssize_t bucket_size = (raw_bucket_iter_p - table_p->buckets[block_id]);
int32_t index;
for (index = 0; index < bucket_size; index++)
{
if (table_p->buckets[block_id][index].packed_value == lit_cp.packed_value)
{
break;
}
}
if (index == bucket_size)
{
JERRY_ASSERT ((uint8_t *) (table_p->raw_buckets + table_p->current_bucket_pos) < (uint8_t *) (table_p->buckets));
table_p->buckets[block_id][index] = lit_cp;
table_p->current_bucket_pos++;
}
JERRY_ASSERT (index <= VM_IDX_LITERAL_LAST);
return (vm_idx_t) index;
} /* lit_id_hash_table_insert */
/**
* Lookup literal identifier by pair
*
* @return literal identifier
*/
lit_cpointer_t
lit_id_hash_table_lookup (lit_id_hash_table *table_p, /**< table's header */
vm_idx_t uid, /**< value of byte-code instruction's argument */
vm_instr_counter_t oc) /**< instruction counter of the instruction */
{
JERRY_ASSERT (table_p != NULL);
size_t block_id = oc / BLOCK_SIZE;
JERRY_ASSERT (table_p->buckets[block_id] != NULL);
return table_p->buckets[block_id][uid];
} /* lit_id_hash_table_lookup */
/**
* Dump literal identifiers hash table to snapshot buffer
*
* @return number of bytes dumper - upon success,
* 0 - upon failure
*/
uint32_t
lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
lit_id_hash_table *table_p, /**< hash table to dump */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num, /**< number of literals */
vm_instr_counter_t instrs_num) /**< number of instructions in corresponding
* byte-code array */
{
size_t begin_offset = *in_out_buffer_offset_p;
uint32_t idx_num_total = (uint32_t) table_p->current_bucket_pos;
JERRY_ASSERT (idx_num_total == table_p->current_bucket_pos);
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_total,
sizeof (idx_num_total)))
{
return 0;
}
size_t blocks_num = JERRY_ALIGNUP (instrs_num, BLOCK_SIZE) / BLOCK_SIZE;
for (size_t block_index = 0, next_block_index;
block_index < blocks_num;
)
{
uint32_t idx_num_in_block;
next_block_index = block_index + 1u;
while (next_block_index < blocks_num
&& table_p->buckets[next_block_index] == NULL)
{
next_block_index++;
}
if (next_block_index != blocks_num)
{
idx_num_in_block = (uint32_t) (table_p->buckets[next_block_index] - table_p->buckets[block_index]);
}
else if (table_p->buckets[block_index] != NULL)
{
idx_num_in_block = (uint32_t) (table_p->current_bucket_pos
- (size_t) (table_p->buckets[block_index] - table_p->buckets[0]));
}
else
{
idx_num_in_block = 0;
}
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return 0;
}
for (size_t block_idx_pair_index = 0;
block_idx_pair_index < idx_num_in_block;
block_idx_pair_index++)
{
lit_cpointer_t lit_cp = table_p->buckets[block_index][block_idx_pair_index];
uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num);
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset)))
{
return 0;
}
}
while (++block_index < next_block_index)
{
idx_num_in_block = 0;
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return 0;
}
}
}
size_t bytes_written = (*in_out_buffer_offset_p - begin_offset);
JERRY_ASSERT (bytes_written == (uint32_t) bytes_written);
return (uint32_t) bytes_written;
} /* lit_id_hash_table_dump_for_snapshot */
/**
* Load literal identifiers hash table from specified snapshot buffer
*
* @return true - upon successful load (i.e. data in snapshot is consistent),
* false - upon failure (in case, snapshot is incorrect)
*/
bool
lit_id_hash_table_load_from_snapshot (size_t blocks_count, /**< number of byte-code blocks
* in corresponding byte-code array */
uint32_t idx_num_total, /**< total number of (byte-code block, idx)
* pairs in snapshot */
const uint8_t *idx_to_lit_map_p, /**< idx-to-lit map in snapshot */
size_t idx_to_lit_map_size, /**< size of the map */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals in snapshot */
uint8_t *buffer_for_hash_table_p, /**< buffer to initialize hash table in */
size_t buffer_for_hash_table_size) /**< size of the buffer */
{
lit_id_hash_table *hash_table_p = lit_id_hash_table_init (buffer_for_hash_table_p,
buffer_for_hash_table_size,
idx_num_total,
blocks_count);
size_t idx_to_lit_map_offset = 0;
uint32_t idx_num_counter = 0;
for (size_t block_idx = 0; block_idx < blocks_count; block_idx++)
{
uint32_t idx_num_in_block;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
idx_to_lit_map_size,
&idx_to_lit_map_offset,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return false;
}
hash_table_p->buckets[block_idx] = hash_table_p->raw_buckets + hash_table_p->current_bucket_pos;
if (idx_num_counter + idx_num_in_block < idx_num_counter)
{
return false;
}
idx_num_counter += idx_num_in_block;
if (idx_num_counter > idx_num_total)
{
return false;
}
for (uint32_t idx_in_block = 0; idx_in_block < idx_num_in_block; idx_in_block++)
{
uint32_t lit_offset_from_snapshot;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
idx_to_lit_map_size,
&idx_to_lit_map_offset,
&lit_offset_from_snapshot,
sizeof (lit_offset_from_snapshot)))
{
return false;
}
/**
* TODO: implement binary search here
*/
lit_cpointer_t lit_cp = rcs_cpointer_null_cp ();
uint32_t i;
for (i = 0; i < literals_num; i++)
{
if (lit_map_p[i].literal_offset == lit_offset_from_snapshot)
{
lit_cp.packed_value = lit_map_p[i].literal_id.packed_value;
break;
}
}
if (i == literals_num)
{
return false;
}
JERRY_ASSERT (hash_table_p->current_bucket_pos < idx_num_total);
hash_table_p->raw_buckets[hash_table_p->current_bucket_pos++] = lit_cp;
}
}
return true;
} /* lit_id_hash_table_load_from_snapshot */
/**
* @}
* @}
* @}
*/
@@ -1,41 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef LIT_ID_HASH_TABLE
#define LIT_ID_HASH_TABLE
#include "jrt.h"
#include "ecma-globals.h"
#include "opcodes.h"
#include "lit-literal.h"
#include "lit-snapshot.h"
typedef struct
{
size_t current_bucket_pos;
lit_cpointer_t *raw_buckets;
lit_cpointer_t **buckets;
} lit_id_hash_table;
lit_id_hash_table *lit_id_hash_table_init (uint8_t *, size_t, size_t, size_t);
size_t lit_id_hash_table_get_size_for_table (size_t, size_t);
void lit_id_hash_table_free (lit_id_hash_table *);
vm_idx_t lit_id_hash_table_insert (lit_id_hash_table *,vm_instr_counter_t, lit_cpointer_t);
lit_cpointer_t lit_id_hash_table_lookup (lit_id_hash_table *, vm_idx_t, vm_instr_counter_t);
uint32_t lit_id_hash_table_dump_for_snapshot (uint8_t *, size_t, size_t *, lit_id_hash_table *,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, vm_instr_counter_t);
bool lit_id_hash_table_load_from_snapshot (size_t, uint32_t, const uint8_t *, size_t,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, uint8_t *, size_t);
#endif /* LIT_ID_HASH_TABLE */
-216
View File
@@ -1,216 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 contains macros to define and use stacks.
Use macro STACK or STATIC_STACK to create stack variable and define all necessaty routines.
Also, define variable with name NAME##_global_size. If the variable more than 0,
first NAME##_global_size element will remain untouched during STACK_PUSH and STACK_POP operations.
Before using the stack, init it by calling STACK_INIT macro.
Use macros STACK_PUSH, STACK_POP, STACK_DROP, STACK_CLEAN and STACK_HEAD to manipulate the stack.
DO NOT FORGET to free stack memory by calling STACK_FREE macro.
For check usage of stack during a function, use STACK_DECLARE_USAGE and STACK_CHECK_USAGE macros.
For the purpose of memory fragmentation reduction, the memory is allocated by chunks and them are
used to store data. The chunks are connected to each other in manner of double-linked list.
Macro STACK_CONVERT_TO_RAW_DATA allocates memory, so use it after finishing working with the stack.
Example (parser.c):
enum
{
temp_name,
min_temp_name,
max_temp_name,
temp_names_global_size
};
STACK (temp_names, uint8_t, uint8_t)
#define GLOBAL(NAME, VAR) \
STACK_ELEMENT (NAME, VAR)
#define MAX_TEMP_NAME() \
GLOBAL (temp_names, max_temp_name)
#define MIN_TEMP_NAME() \
GLOBAL (temp_names, min_temp_name)
#define TEMP_NAME() \
GLOBAL (temp_names, temp_name)
void
parser_init (void)
{
STACK_INIT (temp_names)
}
void
parser_free (void)
{
STACK_FREE (temp_names)
}
*/
#ifndef STACK_H
#define STACK_H
#include "array-list.h"
#define DEFINE_STACK_TYPE(NAME, TYPE) \
typedef TYPE NAME##_stack_value_type; \
typedef struct \
{ \
array_list data; \
} \
NAME##_stack;
#define STACK_INIT(NAME) \
do { \
NAME.data = array_list_init (sizeof (NAME##_stack_value_type)); \
} while (0)
#define STACK_FREE(NAME) \
do { \
array_list_free (NAME.data); \
NAME.data = null_list; \
} while (0)
#define DEFINE_STACK_ELEMENT(NAME, TYPE) \
static TYPE NAME##_stack_element (size_t) __attr_unused___; \
static TYPE NAME##_stack_element (size_t elem) { \
return *((TYPE *) array_list_element (NAME.data, elem)); \
}
#define DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \
static void set_##NAME##_stack_element (size_t, TYPE) __attr_unused___; \
static void set_##NAME##_stack_element (size_t elem, TYPE value) { \
array_list_set_element (NAME.data, elem, &value); \
}
#define DEFINE_STACK_HEAD(NAME, TYPE) \
static TYPE NAME##_stack_head (size_t) __attr_unused___; \
static TYPE NAME##_stack_head (size_t elem) { \
return *((TYPE *) array_list_last_element (NAME.data, elem)); \
}
#define DEFINE_SET_STACK_HEAD(NAME, TYPE) \
static void set_##NAME##_stack_head (size_t, TYPE) __attr_unused___; \
static void set_##NAME##_stack_head (size_t elem, TYPE value) { \
array_list_set_last_element (NAME.data, elem, &value); \
}
#define DEFINE_STACK_PUSH(NAME, TYPE) \
static void NAME##_stack_push (TYPE) __attr_unused___; \
static void NAME##_stack_push (TYPE value) { \
NAME.data = array_list_append (NAME.data, &value); \
}
#define STACK_PUSH(NAME, VALUE) \
do { NAME##_stack_push (VALUE); } while (0)
#define STACK_DROP(NAME, I) \
do { \
for (size_t i = 0, till = (size_t) (I); i < till; i++) { \
array_list_drop_last (NAME.data); } } while (0)
#define STACK_CLEAN(NAME) \
STACK_DROP (NAME, NAME.current - NAME##_global_size);
#define STACK_HEAD(NAME, I) \
NAME##_stack_head ((size_t) (I))
#define STACK_SET_HEAD(NAME, I, VALUE) \
do { set_##NAME##_stack_head ((size_t) (I), VALUE); } while (0)
#define STACK_INCR_HEAD(NAME, I) \
do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) + 1)); } while (0)
#define STACK_DECR_HEAD(NAME, I) \
do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) - 1)); } while (0)
#define STACK_TOP(NAME) \
STACK_HEAD (NAME, 1)
#define STACK_SWAP(NAME) \
do { \
NAME##_stack_value_type temp = STACK_TOP (NAME); \
STACK_SET_HEAD (NAME, 1, STACK_HEAD (NAME, 2)); \
STACK_SET_HEAD (NAME, 2, temp); \
} while (0)
#define STACK_SIZE(NAME) \
array_list_len (NAME.data)
#define STACK_ELEMENT(NAME, I) \
NAME##_stack_element ((size_t) (I))
#define STACK_SET_ELEMENT(NAME, I, VALUE) \
do { set_##NAME##_stack_element ((size_t) I, VALUE); } while (0)
#define STACK_CONVERT_TO_RAW_DATA(NAME, DATA) \
do { DATA = convert_##NAME##_to_raw_data (); } while (0)
#define STACK_INCR_ELEMENT(NAME, I) \
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT (NAME, I) + 1)); } while (0)
#define STACK_DECR_ELEMENT(NAME, I) \
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT (NAME, I) - 1)); } while (0)
#define STACK_ITERATE(NAME, VAL, FROM) \
for (size_t NAME##_i = FROM; \
NAME##_i < array_list_len (NAME.data); \
NAME##_i++) \
{ \
NAME##_stack_value_type VAL = STACK_ELEMENT (NAME, NAME##_i);
#define STACK_ITERATE_END() \
}
#define STACK_ITERATE_VARG_SET(NAME, FUNC, FROM, ...) \
do { for (size_t i = FROM; i < array_list_len (NAME.data); i++) { \
STACK_SET_ELEMENT (NAME, i, FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__)); \
} } while (0)
#define STACK(NAME, TYPE) \
DEFINE_STACK_TYPE (NAME, TYPE) \
NAME##_stack NAME; \
DEFINE_STACK_ELEMENT (NAME, TYPE) \
DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \
DEFINE_STACK_HEAD (NAME, TYPE) \
DEFINE_SET_STACK_HEAD (NAME, TYPE) \
DEFINE_STACK_PUSH (NAME, TYPE)
#define STATIC_STACK(NAME, TYPE) \
DEFINE_STACK_TYPE (NAME, TYPE) \
static NAME##_stack NAME; \
DEFINE_STACK_ELEMENT (NAME, TYPE) \
DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \
DEFINE_STACK_HEAD (NAME, TYPE) \
DEFINE_SET_STACK_HEAD (NAME, TYPE) \
DEFINE_STACK_PUSH (NAME, TYPE)
#ifndef JERRY_NDEBUG
#define STACK_DECLARE_USAGE(NAME) \
size_t NAME##_current = array_list_len (NAME.data);
#define STACK_CHECK_USAGE(NAME) \
do { \
JERRY_ASSERT (array_list_len (NAME.data) == NAME##_current); \
} while (0)
#else
#define STACK_DECLARE_USAGE(NAME) ;
#define STACK_CHECK_USAGE(NAME) ;
#endif /* JERRY_NDEBUG */
#endif /* STACK_H */
+262
View File
@@ -0,0 +1,262 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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 "common.h"
#include "ecma-helpers.h"
#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
/**
* Checks whether the next UTF8 character is a valid identifier start.
*
* @return non-zero if it is.
*/
int
util_is_identifier_start (const uint8_t *src_p) /* pointer to a vaild UTF8 character */
{
if (*src_p <= 127)
{
return util_is_identifier_start_character (*src_p);
}
return util_is_identifier_start_character (lit_utf8_peek_next (src_p));
} /* util_is_identifier_start */
/**
* Checks whether the next UTF8 character is a valid identifier part.
*
* @return non-zero if it is.
*/
int
util_is_identifier_part (const uint8_t *src_p) /* pointer to a vaild UTF8 character */
{
if (*src_p <= 127)
{
return util_is_identifier_part_character (*src_p);
}
return util_is_identifier_part_character (lit_utf8_peek_next (src_p));
} /* util_is_identifier_part */
/**
* Checks whether the character is a valid identifier start.
*
* @return non-zero if it is.
*/
int
util_is_identifier_start_character (uint16_t chr) /**< EcmaScript character */
{
if (chr <= 127)
{
return (((chr | 0x20) >= LIT_CHAR_LOWERCASE_A && (chr | 0x20) <= LIT_CHAR_LOWERCASE_Z)
|| chr == LIT_CHAR_DOLLAR_SIGN
|| chr == LIT_CHAR_UNDERSCORE);
}
return lit_char_is_unicode_letter (chr);
} /* util_is_identifier_start_character */
/**
* Checks whether the character is a valid identifier part.
*
* @return non-zero if it is.
*/
int
util_is_identifier_part_character (uint16_t chr) /**< EcmaScript character */
{
if (chr <= 127)
{
return (((chr | 0x20) >= LIT_CHAR_LOWERCASE_A && (chr | 0x20) <= LIT_CHAR_LOWERCASE_Z)
|| (chr >= LIT_CHAR_0 && chr <= LIT_CHAR_9)
|| chr == LIT_CHAR_DOLLAR_SIGN
|| chr == LIT_CHAR_UNDERSCORE);
}
return (lit_char_is_unicode_letter (chr)
|| lit_char_is_unicode_combining_mark (chr)
|| lit_char_is_unicode_digit (chr)
|| lit_char_is_unicode_connector_punctuation (chr));
} /* util_is_identifier_part_character */
/**
* Converts a character to UTF8 bytes.
*
* @return length of the UTF8 representation.
*/
size_t
util_to_utf8_bytes (uint8_t *dst_p, /**< destination buffer */
uint16_t chr) /**< EcmaScript character */
{
if (!(chr & ~0x007f))
{
/* 00000000 0xxxxxxx -> 0xxxxxxx */
*dst_p = (uint8_t) chr;
return 1;
}
if (!(chr & ~0x07ff))
{
/* 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx */
*(dst_p++) = (uint8_t) (0xc0 | ((chr >> 6) & 0x1f));
*dst_p = (uint8_t) (0x80 | (chr & 0x3f));
return 2;
}
/* zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx */
*(dst_p++) = (uint8_t) (0xe0 | ((chr >> 12) & 0x0f));
*(dst_p++) = (uint8_t) (0x80 | ((chr >> 6) & 0x3f));
*dst_p = (uint8_t) (0x80 | (chr & 0x3f));
return 3;
} /* util_to_utf8_bytes */
/**
* Returns the length of the UTF8 representation of a character.
*
* @return length of the UTF8 representation.
*/
size_t
util_get_utf8_length (uint16_t chr) /**< EcmaScript character */
{
if (!(chr & ~0x007f))
{
/* 00000000 0xxxxxxx */
return 1;
}
if (!(chr & ~0x07ff))
{
/* 00000yyy yyxxxxxx */
return 2;
}
/* zzzzyyyy yyxxxxxx */
return 3;
} /* util_get_utf8_length */
/**
* Free literal.
*/
void
util_free_literal (lexer_literal_t *literal_p) /**< literal */
{
if (literal_p->type == LEXER_IDENT_LITERAL
|| literal_p->type == LEXER_STRING_LITERAL)
{
if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR))
{
PARSER_FREE ((uint8_t *) literal_p->u.char_p);
}
}
else if ((literal_p->type == LEXER_FUNCTION_LITERAL)
|| (literal_p->type == LEXER_REGEXP_LITERAL))
{
ecma_bytecode_deref (literal_p->u.bytecode_p);
}
} /* util_free_literal */
#ifdef PARSER_DUMP_BYTE_CODE
/**
* Debug utility to print a character sequence.
*/
static void
util_print_chars (const uint8_t *char_p, /**< character pointer */
size_t size) /**< size */
{
while (size > 0)
{
printf ("%c", *char_p++);
size--;
}
} /* util_print_chars */
/**
* Debug utility to print a number.
*/
static void
util_print_number (ecma_number_t num_p) /**< number to print */
{
lit_utf8_byte_t str_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
lit_utf8_size_t str_size = ecma_number_to_utf8_string (num_p, str_buf, sizeof (str_buf));
str_buf[str_size] = 0;
printf ("%s", str_buf);
} /* util_print_number */
/**
* Print literal.
*/
void
util_print_literal (lexer_literal_t *literal_p) /**< literal */
{
if (literal_p->type == LEXER_IDENT_LITERAL)
{
if (literal_p->status_flags & LEXER_FLAG_VAR)
{
printf ("var_ident(");
}
else
{
printf ("ident(");
}
util_print_chars (literal_p->u.char_p, literal_p->prop.length);
}
else if (literal_p->type == LEXER_FUNCTION_LITERAL)
{
printf ("function");
return;
}
else if (literal_p->type == LEXER_STRING_LITERAL)
{
printf ("string(");
util_print_chars (literal_p->u.char_p, literal_p->prop.length);
}
else if (literal_p->type == LEXER_NUMBER_LITERAL)
{
lit_literal_t literal = lit_get_literal_by_cp (literal_p->u.value);
printf ("number(");
util_print_number (lit_number_literal_get_number (literal));
}
else if (literal_p->type == LEXER_REGEXP_LITERAL)
{
printf ("regexp");
return;
}
else
{
printf ("unknown");
return;
}
printf (")");
} /* util_print_literal */
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
+167
View File
@@ -0,0 +1,167 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <setjmp.h>
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
#ifndef JERRY_NDEBUG
#define PARSER_DEBUG
#endif
#ifndef JERRY_NDEBUG
/* Note: This flag is independent from debug mode. */
#define PARSER_DUMP_BYTE_CODE
#endif
#include "ecma-globals.h"
#include "ecma-regexp-object.h"
#include "lit-literal.h"
#include "mem-heap.h"
/* The utilites here are just for compiling purposes, JS
* engines should have an optimized version for them. */
/* Malloc functions. */
#define PARSER_MALLOC(size) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM)
#define PARSER_FREE(ptr) mem_heap_free_block ((void *) ptr)
#define PARSER_MALLOC_LOCAL(size) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM)
#define PARSER_FREE_LOCAL(ptr) mem_heap_free_block (ptr)
/* UTF character management. Only ASCII characters are
* supported for simplicity. */
int util_is_identifier_start (const uint8_t *);
int util_is_identifier_part (const uint8_t *);
int util_is_identifier_start_character (uint16_t);
int util_is_identifier_part_character (uint16_t);
size_t util_to_utf8_bytes (uint8_t *, uint16_t);
size_t util_get_utf8_length (uint16_t);
/* Immediate management. */
/**
* Literal types.
*
* The LEXER_UNUSED_LITERAL type is internal and
* used for various purposes.
*/
typedef enum
{
LEXER_IDENT_LITERAL = 0, /**< identifier literal */
LEXER_STRING_LITERAL = 1, /**< string literal */
LEXER_NUMBER_LITERAL = 2, /**< number literal */
LEXER_FUNCTION_LITERAL = 3, /**< function literal */
LEXER_REGEXP_LITERAL = 4, /**< regexp literal */
LEXER_UNUSED_LITERAL = 5, /**< unused literal, can only be
used by the byte code generator. */
} lexer_literal_type_t;
/* Flags for status_flags. */
/* Local identifier (var, function arg). */
#define LEXER_FLAG_VAR 0x01
/* This local identifier cannot be stored in register. */
#define LEXER_FLAG_NO_REG_STORE 0x02
/* This local identifier is initialized with a value. */
#define LEXER_FLAG_INITIALIZED 0x04
/* This local identifier has a reference to the function itself. */
#define LEXER_FLAG_FUNCTION_NAME 0x08
/* This local identifier is a function argument. */
#define LEXER_FLAG_FUNCTION_ARGUMENT 0x10
/* No space is allocated for this character literal. */
#define LEXER_FLAG_SOURCE_PTR 0x20
/* Initialize this variable after the byte code is freed. */
#define LEXER_FLAG_LATE_INIT 0x40
/**
* Literal data.
*/
typedef struct
{
union
{
lit_cpointer_t value; /**< literal value (not processed by the parser) */
const uint8_t *char_p; /**< character value */
ecma_compiled_code_t *bytecode_p; /**< compiled function or regexp pointer */
uint32_t source_data; /**< encoded source literal */
} u;
#ifdef PARSER_DUMP_BYTE_CODE
struct
#else
union
#endif
{
uint16_t length; /**< length of ident / string literal */
uint16_t index; /**< real index during post processing */
} prop;
uint8_t type; /**< type of the literal */
uint8_t status_flags; /**< status flags */
} lexer_literal_t;
void util_free_literal (lexer_literal_t *);
#ifdef PARSER_DUMP_BYTE_CODE
void util_print_literal (lexer_literal_t *);
#endif /* PARSER_DUMP_BYTE_CODE */
/* TRY/CATCH block */
#define PARSER_TRY_CONTEXT(context_name) \
jmp_buf context_name
#define PARSER_THROW(context_name) \
longjmp (context_name, 1);
#define PARSER_TRY(context_name) \
{ \
if (!setjmp (context_name)) \
{ \
#define PARSER_CATCH \
} \
else \
{
#define PARSER_TRY_END \
} \
}
/* Other */
#define PARSER_INLINE inline
#define PARSER_NOINLINE __attribute__ ((noinline))
#endif /* !COMMON_H */
File diff suppressed because it is too large Load Diff
+270
View File
@@ -0,0 +1,270 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef JS_LEXER_H
#define JS_LEXER_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_lexer Lexer
* @{
*/
/**
* Lexer token types.
*/
typedef enum
{
LEXER_EOS, /**< end of source */
/* Primary expressions */
LEXER_LITERAL, /**< literal token */
LEXER_KEYW_THIS, /**< this */
LEXER_LIT_TRUE, /**< true (not a keyword!) */
LEXER_LIT_FALSE, /**< false (not a keyword!) */
LEXER_LIT_NULL, /**< null (not a keyword!) */
/* Unary operators
* IMPORTANT: update CBC_UNARY_OP_TOKEN_TO_OPCODE and
* CBC_UNARY_LVALUE_OP_TOKEN_TO_OPCODE after changes. */
#define LEXER_IS_UNARY_OP_TOKEN(token_type) \
((token_type) >= LEXER_PLUS && (token_type) <= LEXER_DECREASE)
#define LEXER_IS_UNARY_LVALUE_OP_TOKEN(token_type) \
((token_type) >= LEXER_KEYW_DELETE && (token_type) <= LEXER_DECREASE)
LEXER_PLUS, /**< + */
LEXER_NEGATE, /**< - */
LEXER_LOGICAL_NOT, /**< ! */
LEXER_BIT_NOT, /**< ~ */
LEXER_KEYW_VOID, /**< void */
LEXER_KEYW_TYPEOF, /**< typeof */
LEXER_KEYW_DELETE, /**< delete */
LEXER_INCREASE, /**< ++ */
LEXER_DECREASE, /**< -- */
/* Binary operators
* IMPORTANT: update CBC_BINARY_OP_TOKEN_TO_OPCODE,
* CBC_BINARY_LVALUE_OP_TOKEN_TO_OPCODE and
* parser_binary_precedence_table after changes. */
#define LEXER_IS_BINARY_OP_TOKEN(token_type) \
((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_MODULO)
#define LEXER_IS_BINARY_LVALUE_TOKEN(token_type) \
((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_ASSIGN_BIT_XOR)
#define LEXER_FIRST_BINARY_OP LEXER_ASSIGN
LEXER_ASSIGN, /**< = (prec: 3) */
LEXER_ASSIGN_ADD, /**< += (prec: 3) */
LEXER_ASSIGN_SUBTRACT, /**< -= (prec: 3) */
LEXER_ASSIGN_MULTIPLY, /**< *= (prec: 3) */
LEXER_ASSIGN_DIVIDE, /**< /= (prec: 3) */
LEXER_ASSIGN_MODULO, /**< %= (prec: 3) */
LEXER_ASSIGN_LEFT_SHIFT, /**< <<= (prec: 3) */
LEXER_ASSIGN_RIGHT_SHIFT, /**< >>= (prec: 3) */
LEXER_ASSIGN_UNS_RIGHT_SHIFT, /**< >>>= (prec: 3) */
LEXER_ASSIGN_BIT_AND, /**< &= (prec: 3) */
LEXER_ASSIGN_BIT_OR, /**< |= (prec: 3) */
LEXER_ASSIGN_BIT_XOR, /**< ^= (prec: 3) */
LEXER_QUESTION_MARK, /**< ? (prec: 4) */
LEXER_LOGICAL_OR, /**< || (prec: 5) */
LEXER_LOGICAL_AND, /**< && (prec: 6) */
LEXER_BIT_OR, /**< | (prec: 7) */
LEXER_BIT_XOR, /**< ^ (prec: 8) */
LEXER_BIT_AND, /**< & (prec: 9) */
LEXER_EQUAL, /**< == (prec: 10) */
LEXER_NOT_EQUAL, /**< != (prec: 10) */
LEXER_STRICT_EQUAL, /**< === (prec: 10) */
LEXER_STRICT_NOT_EQUAL, /**< !== (prec: 10) */
LEXER_LESS, /**< < (prec: 11) */
LEXER_GREATER, /**< > (prec: 11) */
LEXER_LESS_EQUAL, /**< <= (prec: 11) */
LEXER_GREATER_EQUAL, /**< >= (prec: 11) */
LEXER_KEYW_IN, /**< in (prec: 11) */
LEXER_KEYW_INSTANCEOF, /**< instanceof (prec: 11) */
LEXER_LEFT_SHIFT, /**< << (prec: 12) */
LEXER_RIGHT_SHIFT, /**< >> (prec: 12) */
LEXER_UNS_RIGHT_SHIFT, /**< >>> (prec: 12) */
LEXER_ADD, /**< + (prec: 13) */
LEXER_SUBTRACT, /**< - (prec: 13) */
LEXER_MULTIPLY, /**< * (prec: 14) */
LEXER_DIVIDE, /**< / (prec: 14) */
LEXER_MODULO, /**< % (prec: 14) */
LEXER_LEFT_BRACE, /**< { */
LEXER_LEFT_PAREN, /**< ( */
LEXER_LEFT_SQUARE, /**< [ */
LEXER_RIGHT_BRACE, /**< } */
LEXER_RIGHT_PAREN, /**<_) */
LEXER_RIGHT_SQUARE, /**< ] */
LEXER_DOT, /**< . */
LEXER_SEMICOLON, /**< ; */
LEXER_COLON, /**< : */
LEXER_COMMA, /**< , */
LEXER_KEYW_BREAK, /**< break */
LEXER_KEYW_DO, /**< do */
LEXER_KEYW_CASE, /**< case */
LEXER_KEYW_ELSE, /**< else */
LEXER_KEYW_NEW, /**< new */
LEXER_KEYW_VAR, /**< var */
LEXER_KEYW_CATCH, /**< catch */
LEXER_KEYW_FINALLY, /**< finally */
LEXER_KEYW_RETURN, /**< return */
LEXER_KEYW_CONTINUE, /**< continue */
LEXER_KEYW_FOR, /**< for */
LEXER_KEYW_SWITCH, /**< switch */
LEXER_KEYW_WHILE, /**< while */
LEXER_KEYW_DEBUGGER, /**< debugger */
LEXER_KEYW_FUNCTION, /**< function */
LEXER_KEYW_WITH, /**< with */
LEXER_KEYW_DEFAULT, /**< default */
LEXER_KEYW_IF, /**< if */
LEXER_KEYW_THROW, /**< throw */
LEXER_KEYW_TRY, /**< try */
/* These are virtual tokens. */
LEXER_EXPRESSION_START, /**< expression start */
LEXER_PROPERTY_GETTER, /**< property getter function */
LEXER_PROPERTY_SETTER, /**< property setter function */
LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
/* Future reserved words: these keywords
* must form a group after all other keywords. */
#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_CLASS
LEXER_KEYW_CLASS, /**< class */
LEXER_KEYW_ENUM, /**< enum */
LEXER_KEYW_EXTENDS, /**< extends */
LEXER_KEYW_SUPER, /**< super */
LEXER_KEYW_CONST, /**< const */
LEXER_KEYW_EXPORT, /**< export */
LEXER_KEYW_IMPORT, /**< import */
/* Future strict reserved words: these keywords
* must form a group after future reserved words. */
#define LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD LEXER_KEYW_IMPLEMENTS
LEXER_KEYW_IMPLEMENTS, /**< implements */
LEXER_KEYW_LET, /**< let */
LEXER_KEYW_PRIVATE, /**< private */
LEXER_KEYW_PUBLIC, /**< public */
LEXER_KEYW_YIELD, /**< yield */
LEXER_KEYW_INTERFACE, /**< interface */
LEXER_KEYW_PACKAGE, /**< package */
LEXER_KEYW_PROTECTED, /**< protected */
LEXER_KEYW_STATIC, /**< static */
} lexer_token_type_t;
#define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2
#define LEXER_NEWLINE_LS_PS_BYTE_23(source) ((source)[1] == 0x80 && ((source)[2] | 0x1) == 0xa9)
#define LEXER_UTF8_4BYTE_START 0xf0
#define LEXER_IS_LEFT_BRACKET(type) \
((type) == LEXER_LEFT_BRACE || (type) == LEXER_LEFT_PAREN || (type) == LEXER_LEFT_SQUARE)
#define LEXER_IS_RIGHT_BRACKET(type) \
((type) == LEXER_RIGHT_BRACE || (type) == LEXER_RIGHT_PAREN || (type) == LEXER_RIGHT_SQUARE)
#define LEXER_UNARY_OP_TOKEN_TO_OPCODE(token_type) \
((((token_type) - LEXER_PLUS) * 2) + CBC_PLUS)
#define LEXER_UNARY_LVALUE_OP_TOKEN_TO_OPCODE(token_type) \
((((token_type) - LEXER_KEYW_DELETE) * 6) + CBC_DELETE)
#define LEXER_BINARY_OP_TOKEN_TO_OPCODE(token_type) \
((cbc_opcode_t) ((((token_type) - LEXER_BIT_OR) * 3) + CBC_BIT_OR))
#define LEXER_BINARY_LVALUE_OP_TOKEN_TO_OPCODE(token_type) \
((cbc_opcode_t) ((((token_type) - LEXER_ASSIGN_ADD) * 2) + CBC_ASSIGN_ADD))
#define LEXER_TO_ASCII_LOWERCASE(character) ((character) | 0x20)
/**
* Lexer literal object types.
*/
typedef enum
{
LEXER_LITERAL_OBJECT_ANY, /**< unspecified object type */
LEXER_LITERAL_OBJECT_EVAL, /**< reference is equal to eval */
LEXER_LITERAL_OBJECT_ARGUMENTS, /**< reference is equal to arguments */
} lexer_literal_object_type_t;
/**
* Lexer number types.
*/
typedef enum
{
LEXER_NUMBER_DECIMAL, /**< decimal number */
LEXER_NUMBER_HEXADECIMAL, /**< hexadecimal number */
LEXER_NUMBER_OCTAL, /**< octal number */
} lexer_number_type_t;
/**
* Lexer character (string / identifier) literal data.
*/
typedef struct
{
const uint8_t *char_p; /**< start of identifier or string token */
uint16_t length; /**< length or index of a literal */
uint8_t type; /**< type of the current literal */
uint8_t has_escape; /**< has escape sequences */
} lexer_lit_location_t;
/**
* Range of input string which processing is postponed.
*/
typedef struct
{
const uint8_t *source_p; /**< next source byte */
const uint8_t *source_end_p; /**< last source byte */
parser_line_counter_t line; /**< token start line */
parser_line_counter_t column; /**< token start column */
} lexer_range_t;
/**
* Lexer token.
*/
typedef struct
{
uint8_t type; /**< token type */
uint8_t literal_is_reserved; /**< future reserved keyword
* (when char_literal.type is LEXER_IDENT_LITERAL) */
uint8_t extra_value; /**< helper value for different purposes */
uint8_t was_newline; /**< newline occured before this token */
parser_line_counter_t line; /**< token start line */
parser_line_counter_t column; /**< token start column */
lexer_lit_location_t lit_location; /**< extra data for character literals */
} lexer_token_t;
/**
* Literal data set by lexer_construct_literal_object.
*/
typedef struct
{
lexer_literal_t *literal_p; /**< pointer to the literal object */
uint16_t index; /**< literal index */
uint8_t type; /**< literal object type */
} lexer_lit_object_t;
/**
* @}
* @}
* @}
*/
#endif /* !JS_LEXER_H */
File diff suppressed because it is too large Load Diff
+378
View File
@@ -0,0 +1,378 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef JS_PARSER_INTERNAL_H
#define JS_PARSER_INTERNAL_H
#include "common.h"
#include "js-parser.h"
#include "js-parser-limits.h"
#include "js-lexer.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_internals Internals
* @{
*/
/* General parser flags. */
#define PARSER_IS_STRICT 0x00001u
#define PARSER_IS_FUNCTION 0x00002u
#define PARSER_IS_CLOSURE 0x00004u
#define PARSER_IS_PROPERTY_GETTER 0x00008u
#define PARSER_IS_PROPERTY_SETTER 0x00010u
#define PARSER_IS_FUNC_EXPRESSION 0x00020u
#define PARSER_HAS_NON_STRICT_ARG 0x00040u
#define PARSER_INSIDE_WITH 0x00080u
#define PARSER_RESOLVE_THIS_FOR_CALLS 0x00100u
#define PARSER_NAMED_FUNCTION_EXP 0x00200u
#define PARSER_HAS_INITIALIZED_VARS 0x00400u
#define PARSER_NO_END_LABEL 0x00800u
#define PARSER_NO_REG_STORE 0x01000u
#define PARSER_ARGUMENTS_NEEDED 0x02000u
#define PARSER_ARGUMENTS_NOT_NEEDED 0x04000u
#define PARSER_LEXICAL_ENV_NEEDED 0x08000u
#define PARSER_HAS_LATE_LIT_INIT 0x10000u
/* Expression parsing flags. */
#define PARSE_EXPR 0x00
#define PARSE_EXPR_STATEMENT 0x01
#define PARSE_EXPR_BLOCK 0x02
#define PARSE_EXPR_NO_COMMA 0x04
#define PARSE_EXPR_HAS_LITERAL 0x08
/* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */
#define PARSER_CBC_STREAM_PAGE_SIZE \
((uint32_t) (64 - sizeof (void*)))
#define PARSER_STACK_PAGE_SIZE \
((uint32_t) (((sizeof (void*) > 4) ? 128 : 64) - sizeof (void*)))
/* Avoid compiler warnings for += operations. */
#define PARSER_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
#define PARSER_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
#define PARSER_PLUS_EQUAL_LC(base, value) (base) = (parser_line_counter_t) ((base) + (value))
/**
* Parser boolean type.
*/
typedef enum
{
PARSER_FALSE = 0, /**< false constant */
PARSER_TRUE = 1 /**< true constant */
} parser_boolean_t;
/**
* Argument for a compact-byte code.
*/
typedef struct
{
uint16_t literal_index; /**< literal index argument */
uint16_t value; /**< other argument (second literal or byte). */
uint16_t third_literal_index; /**< literal index argument */
uint8_t literal_type; /**< last literal type */
uint8_t literal_object_type; /**< last literal object type */
} cbc_argument_t;
/* Useful parser macros. */
#define PARSER_CBC_UNAVAILABLE CBC_EXT_OPCODE
#define PARSER_TO_EXT_OPCODE(opcode) ((uint16_t) ((opcode) + 256))
#define PARSER_GET_EXT_OPCODE(opcode) ((opcode) - 256)
#define PARSER_IS_BASIC_OPCODE(opcode) ((opcode) < 256)
#define PARSER_IS_PUSH_LITERAL(opcode) \
((opcode) == CBC_PUSH_LITERAL \
|| (opcode) == CBC_PUSH_TWO_LITERALS \
|| (opcode) == CBC_PUSH_THREE_LITERALS)
#define PARSER_GET_LITERAL(literal_index) \
((lexer_literal_t *) parser_list_get (&context_p->literal_pool, (literal_index)))
#define PARSER_TO_BINARY_OPERATION_WITH_RESULT(opcode) \
(PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_PUSH_RESULT)
#define PARSER_TO_BINARY_OPERATION_WITH_BLOCK(opcode) \
((uint16_t) (PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_BLOCK))
#define PARSER_GET_FLAGS(op) \
(PARSER_IS_BASIC_OPCODE (op) ? cbc_flags[(op)] : cbc_ext_flags[PARSER_GET_EXT_OPCODE (op)])
#define PARSER_OPCODE_IS_RETURN(op) \
((op) == CBC_RETURN || (op) == CBC_RETURN_WITH_BLOCK || (op) == CBC_RETURN_WITH_LITERAL)
#define PARSER_ARGS_EQ(op, types) \
((PARSER_GET_FLAGS (op) & CBC_ARG_TYPES) == (types))
/**
* All data allocated by the parser is
* stored in parser_data_pages in the memory.
*/
typedef struct parser_mem_page_t
{
struct parser_mem_page_t *next_p; /**< next page */
uint8_t bytes[1]; /**< memory bytes */
} parser_mem_page_t;
/**
* Structure for managing parser memory.
*/
typedef struct
{
parser_mem_page_t *first_p; /**< first allocated page */
parser_mem_page_t *last_p; /**< last allocated page */
uint32_t last_position; /**< position of the last allocated byte */
} parser_mem_data_t;
/**
* Parser memory list.
*/
typedef struct
{
parser_mem_data_t data; /**< storage space */
uint32_t page_size; /**< size of each page */
uint32_t item_size; /**< size of each item */
uint32_t item_count; /**< number of items on each page */
} parser_list_t;
/**
* Iterator for parser memory list.
*/
typedef struct
{
parser_list_t *list_p; /**< parser list */
parser_mem_page_t *current_p; /**< currently processed page */
size_t current_position; /**< current position on the page */
} parser_list_iterator_t;
/**
* Parser memory stack.
*/
typedef struct
{
parser_mem_data_t data; /**< storage space */
parser_mem_page_t *free_page_p; /**< space for fast allocation */
} parser_stack_t;
/**
* Iterator for parser memory stack.
*/
typedef struct
{
parser_mem_page_t *current_p; /**< currently processed page */
size_t current_position; /**< current position on the page */
} parser_stack_iterator_t;
/**
* Branch type.
*/
typedef struct
{
parser_mem_page_t *page_p; /**< branch location page */
uint32_t offset; /**< branch location offset */
} parser_branch_t;
/**
* Branch chain type.
*/
typedef struct parser_branch_node_t
{
struct parser_branch_node_t *next_p; /**< next linked list node */
parser_branch_t branch; /**< branch */
} parser_branch_node_t;
/**
* Those members of a context which needs
* to be saved when a sub-function is parsed.
*/
typedef struct parser_saved_context_t
{
/* Parser members. */
uint32_t status_flags; /**< parsing options */
uint16_t stack_depth; /**< current stack depth */
uint16_t stack_limit; /**< maximum stack depth */
struct parser_saved_context_t *prev_context_p; /**< last saved context */
parser_stack_iterator_t last_statement; /**< last statement position */
/* Literal types */
uint16_t argument_count; /**< number of function arguments */
uint16_t register_count; /**< number of registers */
uint16_t literal_count; /**< number of literals */
/* Memory storage members. */
parser_mem_data_t byte_code; /**< byte code buffer */
uint32_t byte_code_size; /**< byte code size for branches */
parser_mem_data_t literal_pool_data; /**< literal list */
#ifdef PARSER_DEBUG
uint16_t context_stack_depth; /**< current context stack depth */
#endif
} parser_saved_context_t;
/**
* Shared parser context.
*/
typedef struct
{
PARSER_TRY_CONTEXT (try_buffer); /**< try_buffer */
parser_error_t error; /**< error code */
void *allocated_buffer_p; /**< dinamically allocated buffer
* which needs to be freed on error */
/* Parser members. */
uint32_t status_flags; /**< status flags */
uint16_t stack_depth; /**< current stack depth */
uint16_t stack_limit; /**< maximum stack depth */
parser_saved_context_t *last_context_p; /**< last saved context */
parser_stack_iterator_t last_statement; /**< last statement position */
/* Lexer members. */
lexer_token_t token; /**< current token */
lexer_lit_object_t lit_object; /**< current literal object */
const uint8_t *source_p; /**< next source byte */
const uint8_t *source_end_p; /**< last source byte */
parser_line_counter_t line; /**< current line */
parser_line_counter_t column; /**< current column */
/* Compact byte code members. */
cbc_argument_t last_cbc; /**< argument of the last cbc */
uint16_t last_cbc_opcode; /**< opcode of the last cbc */
/* Literal types */
uint16_t argument_count; /**< number of function arguments */
uint16_t register_count; /**< number of registers */
uint16_t literal_count; /**< number of literals */
/* Memory storage members. */
parser_mem_data_t byte_code; /**< byte code buffer */
uint32_t byte_code_size; /**< current byte code size for branches */
parser_list_t literal_pool; /**< literal list */
parser_mem_data_t stack; /**< storage space */
parser_mem_page_t *free_page_p; /**< space for fast allocation */
uint8_t stack_top_uint8; /**< top byte stored on the stack */
#ifdef PARSER_DEBUG
/* Variables for debugging / logging. */
uint16_t context_stack_depth; /**< current context stack depth */
#endif /* PARSER_DEBUG */
#ifdef PARSER_DUMP_BYTE_CODE
int is_show_opcodes; /**< show opcodes */
uint32_t total_byte_code_size; /**< total byte code size */
#endif /* PARSER_DUMP_BYTE_CODE */
} parser_context_t;
/* Memory management.
* Note: throws an error if unsuccessful. */
void *parser_malloc (parser_context_t *, size_t);
void parser_free (void *);
void *parser_malloc_local (parser_context_t *, size_t);
void parser_free_local (void *);
/* Parser byte stream. */
void parser_cbc_stream_init (parser_mem_data_t *);
void parser_cbc_stream_free (parser_mem_data_t *);
void parser_cbc_stream_alloc_page (parser_context_t *, parser_mem_data_t *);
/* Parser list. Ensures pointer alignment. */
void parser_list_init (parser_list_t *, uint32_t, uint32_t);
void parser_list_free (parser_list_t *);
void parser_list_reset (parser_list_t *);
void *parser_list_append (parser_context_t *, parser_list_t *);
void *parser_list_get (parser_list_t *, size_t);
void parser_list_iterator_init (parser_list_t *, parser_list_iterator_t *);
void *parser_list_iterator_next (parser_list_iterator_t *);
/* Parser stack. Optimized for pushing bytes.
* Pop functions never throws error. */
void parser_stack_init (parser_context_t *);
void parser_stack_free (parser_context_t *);
void parser_stack_push_uint8 (parser_context_t *, uint8_t);
void parser_stack_pop_uint8 (parser_context_t *);
void parser_stack_push_uint16 (parser_context_t *, uint16_t);
uint16_t parser_stack_pop_uint16 (parser_context_t *);
void parser_stack_push (parser_context_t *, const void *, uint32_t);
void parser_stack_pop (parser_context_t *, void *, uint32_t);
void parser_stack_iterator_skip (parser_stack_iterator_t *, size_t);
void parser_stack_iterator_read (parser_stack_iterator_t *, void *, size_t);
void parser_stack_iterator_write (parser_stack_iterator_t *, const void *, size_t);
/* Compact byte code emitting functions. */
void parser_flush_cbc (parser_context_t *);
void parser_emit_cbc (parser_context_t *, uint16_t);
void parser_emit_cbc_literal (parser_context_t *, uint16_t, uint16_t);
void parser_emit_cbc_literal_from_token (parser_context_t *, uint16_t);
void parser_emit_cbc_call (parser_context_t *, uint16_t, size_t);
void parser_emit_cbc_push_number (parser_context_t *, int);
void parser_emit_cbc_forward_branch (parser_context_t *, uint16_t, parser_branch_t *);
parser_branch_node_t *parser_emit_cbc_forward_branch_item (parser_context_t *, uint16_t, parser_branch_node_t *);
void parser_emit_cbc_backward_branch (parser_context_t *, uint16_t, uint32_t);
void parser_set_branch_to_current_position (parser_context_t *, parser_branch_t *);
void parser_set_breaks_to_current_position (parser_context_t *, parser_branch_node_t *);
void parser_set_continues_to_current_position (parser_context_t *, parser_branch_node_t *);
/* Convenience macros. */
#define parser_emit_cbc_ext(context_p, opcode) \
parser_emit_cbc ((context_p), PARSER_TO_EXT_OPCODE (opcode))
#define parser_emit_cbc_ext_literal(context_p, opcode, literal_index) \
parser_emit_cbc_literal ((context_p), PARSER_TO_EXT_OPCODE (opcode), (literal_index))
#define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \
parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments))
#define parser_emit_cbc_ext_forward_branch(context_p, opcode, branch_p) \
parser_emit_cbc_forward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (branch_p))
#define parser_emit_cbc_ext_backward_branch(context_p, opcode, offset) \
parser_emit_cbc_backward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (offset))
/* Lexer functions */
void lexer_next_token (parser_context_t *);
void lexer_expect_identifier (parser_context_t *, uint8_t);
void lexer_scan_identifier (parser_context_t *, int);
void lexer_expect_object_literal_id (parser_context_t *, int);
void lexer_construct_literal_object (parser_context_t *, lexer_lit_location_t *, uint8_t);
int lexer_construct_number_object (parser_context_t *, int, int);
void lexer_construct_function_object (parser_context_t *, uint32_t);
void lexer_construct_regexp_object (parser_context_t *, int);
int lexer_same_identifiers (lexer_lit_location_t *, lexer_lit_location_t *);
/* Parser functions. */
void parser_parse_expression (parser_context_t *, int);
void parser_parse_statements (parser_context_t *);
void parser_scan_until (parser_context_t *, lexer_range_t *, lexer_token_type_t);
ecma_compiled_code_t *parser_parse_function (parser_context_t *, uint32_t);
void parser_free_jumps (parser_stack_iterator_t);
/* Error management. */
void parser_raise_error (parser_context_t *, parser_error_t);
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_INTERNAL_H */
+99
View File
@@ -0,0 +1,99 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef JS_PARSER_LIMITS_H
#define JS_PARSER_LIMITS_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_internals Internals
* @{
*/
/* Maximum identifier length accepted by the parser.
* Limit: LEXER_MAX_STRING_LENGTH. */
#ifndef PARSER_MAXIMUM_IDENT_LENGTH
#define PARSER_MAXIMUM_IDENT_LENGTH 255
#endif /* PARSER_MAXIMUM_IDENT_LENGTH */
/* Maximum string length.
* Limit: 65535. */
#ifndef PARSER_MAXIMUM_STRING_LENGTH
#define PARSER_MAXIMUM_STRING_LENGTH 65535
#endif /* PARSER_MAXIMUM_STRING_LENGTH */
/* Maximum number of literals.
* Limit: 32767. Recommended: 510, 32767 */
#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS
#define PARSER_MAXIMUM_NUMBER_OF_LITERALS 32767
#endif /* PARSER_MAXIMUM_NUMBER_OF_LITERALS */
/* Maximum number of registers.
* Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS */
#ifndef PARSER_MAXIMUM_NUMBER_OF_REGISTERS
#define PARSER_MAXIMUM_NUMBER_OF_REGISTERS 256
#endif
/* Maximum code size.
* Limit: 16777215. Recommended: 65535, 16777215. */
#ifndef PARSER_MAXIMUM_CODE_SIZE
#define PARSER_MAXIMUM_CODE_SIZE 16777215
#endif
/* Maximum number of values pushed onto the stack by a function.
* Limit: 65500. Recommended: 1024. */
#ifndef PARSER_MAXIMUM_STACK_LIMIT
#define PARSER_MAXIMUM_STACK_LIMIT 1024
#endif /* !PARSER_MAXIMUM_STACK_LIMIT */
/* Checks. */
#if (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535)
#error "Maximum string length is not within range."
#endif /* (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535) */
#if (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH)
#error "Maximum identifier length is not within range."
#endif /* (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH) */
#if (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767)
#error "Maximum number of literals is not within range."
#endif /* (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767) */
#if (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS)
#error "Maximum number of registers is not within range."
#endif /* (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */
#if (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215)
#error "Maximum code size is not within range."
#endif /* (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215) */
#if (PARSER_MAXIMUM_STACK_LIMIT < 16) || (PARSER_MAXIMUM_STACK_LIMIT > 65500)
#error "Maximum function stack usage is not within range."
#endif /* (PARSER_MAXIMUM_STACK_LIMIT < 16) || (PARSER_MAXIMUM_STACK_LIMIT > 65500) */
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_LIMITS_H */
+669
View File
@@ -0,0 +1,669 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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 "js-parser-internal.h"
/** \addtogroup mem Memory allocation
* @{
*
* \addtogroup mem_parser Parser memory manager
* @{
*/
/**********************************************************************/
/* Memory allocation */
/**********************************************************************/
/**
* Allocate memory.
*
* @return allocated memory.
*/
void *
parser_malloc (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory */
{
void *result;
JERRY_ASSERT (size > 0);
result = PARSER_MALLOC (size);
if (result == 0)
{
parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
}
return result;
} /* parser_malloc */
/**
* Free memory allocated by parser_malloc.
*/
void parser_free (void *ptr) /**< pointer to free */
{
PARSER_FREE (ptr);
} /* parser_free */
/**
* Allocate local memory for short term use.
*
* @return allocated memory.
*/
void *
parser_malloc_local (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory */
{
void *result;
JERRY_ASSERT (size > 0);
result = PARSER_MALLOC_LOCAL (size);
if (result == 0)
{
parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
}
return result;
} /* parser_malloc_local */
/**
* Free memory allocated by parser_malloc_local.
*/
void parser_free_local (void *ptr) /**< pointer to free */
{
PARSER_FREE_LOCAL (ptr);
} /* parser_free_local */
/**********************************************************************/
/* Parser data management functions */
/**********************************************************************/
/**
* Initialize parse data.
*/
static void
parser_data_init (parser_mem_data_t *data_p, /**< memory manager */
uint32_t page_size) /**< size of each page */
{
data_p->first_p = NULL;
data_p->last_p = NULL;
data_p->last_position = page_size;
} /* parser_data_init */
/**
* Free parse data.
*/
static void
parser_data_free (parser_mem_data_t *data_p) /**< memory manager */
{
parser_mem_page_t *page_p = data_p->first_p;
while (page_p != NULL)
{
parser_mem_page_t *next_p = page_p->next_p;
parser_free (page_p);
page_p = next_p;
}
} /* parser_data_free */
/**********************************************************************/
/* Parser byte stream management functions */
/**********************************************************************/
/**
* Initialize byte stream.
*/
void
parser_cbc_stream_init (parser_mem_data_t *data_p) /**< memory manager */
{
parser_data_init (data_p, PARSER_CBC_STREAM_PAGE_SIZE);
} /* parser_cbc_stream_init */
/**
* Free byte stream.
*/
void
parser_cbc_stream_free (parser_mem_data_t *data_p) /**< memory manager */
{
parser_data_free (data_p);
} /* parser_cbc_stream_free */
/**
* Appends a byte at the end of the byte stream.
*/
void
parser_cbc_stream_alloc_page (parser_context_t *context_p, /**< context */
parser_mem_data_t *data_p) /**< memory manager */
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE;
parser_mem_page_t *page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
page_p->next_p = NULL;
data_p->last_position = 0;
if (data_p->last_p != NULL)
{
data_p->last_p->next_p = page_p;
}
else
{
data_p->first_p = page_p;
}
data_p->last_p = page_p;
} /* parser_cbc_stream_alloc_page */
/**********************************************************************/
/* Parser list management functions */
/**********************************************************************/
/**
* Initialize parser list.
*/
void
parser_list_init (parser_list_t *list_p, /**< parser list */
uint32_t item_size, /**< size for each page */
uint32_t item_count) /**< number of items on each page */
{
/* Align to pointer size. */
item_size = (uint32_t) (((item_size) + sizeof (void *) - 1) & ~(sizeof (void *) - 1));
parser_data_init (&list_p->data, item_size * item_count);
list_p->page_size = item_size * item_count;
list_p->item_size = item_size;
list_p->item_count = item_count;
} /* parser_list_init */
/**
* Free parser list.
*/
void
parser_list_free (parser_list_t *list_p) /**< parser list */
{
parser_data_free (&list_p->data);
} /* parser_list_free */
/**
* Reset parser list.
*/
void
parser_list_reset (parser_list_t *list_p) /**< parser list */
{
parser_data_init (&list_p->data, list_p->page_size);
} /* parser_list_reset */
/**
* Allocate space for the next item.
*
* @return pointer to the appended item.
*/
void *
parser_list_append (parser_context_t *context_p, /**< context */
parser_list_t *list_p) /**< parser list */
{
parser_mem_page_t *page_p = list_p->data.last_p;
void *result;
if (list_p->data.last_position + list_p->item_size > list_p->page_size)
{
size_t size = sizeof (parser_mem_page_t *) + list_p->page_size;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
page_p->next_p = NULL;
list_p->data.last_position = 0;
if (list_p->data.last_p != NULL)
{
list_p->data.last_p->next_p = page_p;
}
else
{
list_p->data.first_p = page_p;
}
list_p->data.last_p = page_p;
}
result = page_p->bytes + list_p->data.last_position;
list_p->data.last_position += list_p->item_size;
return result;
} /* parser_list_append */
/**
* Return the nth item of the list.
*
* @return pointer to the item.
*/
void *
parser_list_get (parser_list_t *list_p, /**< parser list */
size_t index) /**< item index */
{
size_t item_count = list_p->item_count;
parser_mem_page_t *page_p = list_p->data.first_p;
while (index >= item_count)
{
JERRY_ASSERT (page_p != NULL);
page_p = page_p->next_p;
index -= item_count;
}
JERRY_ASSERT (page_p != NULL);
JERRY_ASSERT (page_p != list_p->data.last_p
|| (index * list_p->item_size < list_p->data.last_position));
return page_p->bytes + (index * list_p->item_size);
} /* parser_list_get */
/**
* Initialize a parser list iterator.
*/
void
parser_list_iterator_init (parser_list_t *list_p, /**< parser list */
parser_list_iterator_t *iterator_p) /**< iterator */
{
iterator_p->list_p = list_p;
iterator_p->current_p = list_p->data.first_p;
iterator_p->current_position = 0;
} /* parser_list_iterator_init */
/**
* Next iterator step.
*
* @return the address of the current item, or NULL at the end.
*/
void *
parser_list_iterator_next (parser_list_iterator_t *iterator_p) /**< iterator */
{
void *result;
if (iterator_p->current_p == NULL)
{
return NULL;
}
result = iterator_p->current_p->bytes + iterator_p->current_position;
iterator_p->current_position += iterator_p->list_p->item_size;
if (iterator_p->current_p->next_p == NULL)
{
if (iterator_p->current_position >= iterator_p->list_p->data.last_position)
{
iterator_p->current_p = NULL;
iterator_p->current_position = 0;
}
}
else if (iterator_p->current_position >= iterator_p->list_p->page_size)
{
iterator_p->current_p = iterator_p->current_p->next_p;
iterator_p->current_position = 0;
}
return result;
} /* parser_list_iterator_next */
/**********************************************************************/
/* Parser stack management functions */
/**********************************************************************/
/* Stack is a reversed storage. */
/**
* Initialize parser stack.
*/
void
parser_stack_init (parser_context_t *context_p) /**< context */
{
parser_data_init (&context_p->stack, PARSER_STACK_PAGE_SIZE);
context_p->free_page_p = NULL;
} /* parser_stack_init */
/**
* Free parser stack.
*/
void
parser_stack_free (parser_context_t *context_p) /**< context */
{
parser_data_free (&context_p->stack);
if (context_p->free_page_p != NULL)
{
parser_free (context_p->free_page_p);
}
} /* parser_stack_free */
/**
* Pushes an uint8_t value onto the stack.
*/
void
parser_stack_push_uint8 (parser_context_t *context_p, /**< context */
uint8_t uint8_value) /**< value pushed onto the stack */
{
parser_mem_page_t *page_p = context_p->stack.first_p;
/* This assert might trigger false positive valgrind errors, when
* parser_stack_push() pushes not fully initialized structures.
* More precisely when the last byte of the structure is uninitialized. */
JERRY_ASSERT (page_p == NULL
|| context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
if (context_p->stack.last_position >= PARSER_STACK_PAGE_SIZE)
{
if (context_p->free_page_p != NULL)
{
page_p = context_p->free_page_p;
context_p->free_page_p = NULL;
}
else
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
}
page_p->next_p = context_p->stack.first_p;
context_p->stack.last_position = 0;
context_p->stack.first_p = page_p;
}
page_p->bytes[context_p->stack.last_position++] = uint8_value;
context_p->stack_top_uint8 = uint8_value;
} /* parser_stack_push_uint8 */
/**
* Pops the last uint8_t value from the stack.
*/
void
parser_stack_pop_uint8 (parser_context_t *context_p) /**< context */
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
context_p->stack.last_position--;
if (context_p->stack.last_position == 0)
{
context_p->stack.first_p = page_p->next_p;
context_p->stack.last_position = PARSER_STACK_PAGE_SIZE;
if (context_p->free_page_p == NULL)
{
context_p->free_page_p = page_p;
}
else
{
parser_free (page_p);
}
page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL);
}
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
} /* parser_stack_pop_uint8 */
/**
* Pushes an uint16_t value onto the stack.
*/
void
parser_stack_push_uint16 (parser_context_t *context_p, /**< context */
uint16_t uint16_value) /**< value pushed onto the stack */
{
if (context_p->stack.last_position + 2 <= PARSER_STACK_PAGE_SIZE)
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
page_p->bytes[context_p->stack.last_position++] = (uint8_t) (uint16_value >> 8);
page_p->bytes[context_p->stack.last_position++] = (uint8_t) uint16_value;
context_p->stack_top_uint8 = (uint8_t) uint16_value;
}
else
{
parser_stack_push_uint8 (context_p, (uint8_t) (uint16_value >> 8));
parser_stack_push_uint8 (context_p, (uint8_t) uint16_value);
}
} /* parser_stack_push_uint16 */
/**
* Pops the last uint16_t value from the stack.
*
* @return the value popped from the stack.
*/
uint16_t
parser_stack_pop_uint16 (parser_context_t *context_p) /**< context */
{
uint32_t value = context_p->stack_top_uint8;
if (context_p->stack.last_position >= 3)
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
value |= ((uint32_t) page_p->bytes[context_p->stack.last_position - 2]) << 8;
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 3];
context_p->stack.last_position -= 2;
}
else
{
parser_stack_pop_uint8 (context_p);
value |= ((uint32_t) context_p->stack_top_uint8) << 8;
parser_stack_pop_uint8 (context_p);
}
return (uint16_t) value;
} /* parser_stack_pop_uint16 */
/**
* Pushes a data onto the stack.
*/
void
parser_stack_push (parser_context_t *context_p, /**< context */
const void *data_p, /* data pushed onto the stack */
uint32_t length) /* length of the data */
{
uint32_t fragment_length = PARSER_STACK_PAGE_SIZE - context_p->stack.last_position;
const uint8_t *bytes_p = (const uint8_t *) data_p;
parser_mem_page_t *page_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
context_p->stack_top_uint8 = bytes_p[length - 1];
if (fragment_length > 0)
{
/* Fill the remaining bytes. */
if (fragment_length > length)
{
fragment_length = length;
}
memcpy (context_p->stack.first_p->bytes + context_p->stack.last_position,
bytes_p,
fragment_length);
if (fragment_length == length)
{
context_p->stack.last_position += length;
return;
}
bytes_p += fragment_length;
length -= fragment_length;
}
if (context_p->free_page_p != NULL)
{
page_p = context_p->free_page_p;
context_p->free_page_p = NULL;
}
else
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
}
page_p->next_p = context_p->stack.first_p;
context_p->stack.first_p = page_p;
memcpy (page_p->bytes, bytes_p, length);
context_p->stack.last_position = length;
} /* parser_stack_push */
/**
* Pop bytes from the top of the stack.
*/
void
parser_stack_pop (parser_context_t *context_p, /**< context */
void *data_p, /* destination buffer, can be NULL */
uint32_t length) /* length of the data */
{
uint8_t *bytes_p = (uint8_t *) data_p;
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (context_p->stack.last_position > length)
{
context_p->stack.last_position -= length;
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
if (bytes_p != NULL)
{
memcpy (bytes_p, context_p->stack.first_p->bytes + context_p->stack.last_position, length);
}
return;
}
JERRY_ASSERT (page_p->next_p != NULL);
length -= context_p->stack.last_position;
if (bytes_p != NULL)
{
memcpy (bytes_p + length, page_p->bytes, context_p->stack.last_position);
}
context_p->stack.first_p = page_p->next_p;
context_p->stack.last_position = PARSER_STACK_PAGE_SIZE - length;
context_p->stack_top_uint8 = page_p->next_p->bytes[context_p->stack.last_position - 1];
if (bytes_p != NULL && length > 0)
{
memcpy (bytes_p, page_p->next_p->bytes + context_p->stack.last_position, length);
}
JERRY_ASSERT (context_p->stack.last_position > 0);
if (context_p->free_page_p == NULL)
{
context_p->free_page_p = page_p;
}
else
{
parser_free (page_p);
}
} /* parser_stack_pop */
/**
* Skip the next n bytes of the stack.
*/
void
parser_stack_iterator_skip (parser_stack_iterator_t *iterator, /**< iterator */
size_t length) /**< number of skipped bytes */
{
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length < iterator->current_position)
{
iterator->current_position -= length;
}
else
{
iterator->current_position = PARSER_STACK_PAGE_SIZE - (length - iterator->current_position);
iterator->current_p = iterator->current_p->next_p;
}
} /* parser_stack_iterator_skip */
/**
* Read bytes from the stack.
*/
void
parser_stack_iterator_read (parser_stack_iterator_t *iterator, /**< iterator */
void *data_p, /* destination buffer */
size_t length) /* length of the data */
{
uint8_t *bytes_p = (uint8_t *) data_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length <= iterator->current_position)
{
memcpy (bytes_p,
iterator->current_p->bytes + iterator->current_position - length,
length);
}
else
{
JERRY_ASSERT (iterator->current_p->next_p != NULL);
length -= iterator->current_position;
memcpy (bytes_p + length,
iterator->current_p->bytes,
iterator->current_position);
memcpy (bytes_p,
iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
length);
}
} /* parser_stack_iterator_read */
/**
* Write bytes onto the stack.
*/
void
parser_stack_iterator_write (parser_stack_iterator_t *iterator, /**< iterator */
const void *data_p, /* destination buffer */
size_t length) /* length of the data */
{
const uint8_t *bytes_p = (const uint8_t *) data_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length <= iterator->current_position)
{
memcpy (iterator->current_p->bytes + iterator->current_position - length,
bytes_p,
length);
}
else
{
JERRY_ASSERT (iterator->current_p->next_p != NULL);
length -= iterator->current_position;
memcpy (iterator->current_p->bytes,
bytes_p + length,
iterator->current_position);
memcpy (iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
bytes_p,
length);
}
} /* parser_stack_iterator_write */
/**
* @}
* @}
*/
+678
View File
@@ -0,0 +1,678 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Scan mode types types.
*/
typedef enum
{
SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */
SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */
SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */
SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning prymary expression end */
SCAN_MODE_STATEMENT, /**< scanning statement */
SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */
SCAN_MODE_PROPERTY_NAME, /**< scanning property name */
} scan_modes_t;
/**
* Scan stack mode types types.
*/
typedef enum
{
SCAN_STACK_HEAD, /**< head */
SCAN_STACK_PAREN_EXPRESSION, /**< parent expression group */
SCAN_STACK_PAREN_STATEMENT, /**< parent stetement group */
SCAN_STACK_COLON_EXPRESSION, /**< colon expression group */
SCAN_STACK_COLON_STATEMENT, /**< colon statement group*/
SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */
SCAN_STACK_OBJECT_LITERAL, /**< object literal group */
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group*/
SCAN_STACK_BLOCK_PROPERTY, /**< block property group */
} scan_stack_modes_t;
/**
* Scan primary expression.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_primary_expression (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_KEYW_NEW:
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW;
break;
}
case LEXER_DIVIDE:
case LEXER_ASSIGN_DIVIDE:
{
lexer_construct_regexp_object (context_p, PARSER_TRUE);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_KEYW_FUNCTION:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION);
*mode = SCAN_MODE_FUNCTION_ARGUMENTS;
break;
}
case LEXER_LEFT_PAREN:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_LEFT_SQUARE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_LEFT_BRACE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
*mode = SCAN_MODE_PROPERTY_NAME;
return PARSER_TRUE;
}
case LEXER_LITERAL:
case LEXER_KEYW_THIS:
case LEXER_LIT_TRUE:
case LEXER_LIT_FALSE:
case LEXER_LIT_NULL:
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_RIGHT_SQUARE:
{
if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
parser_stack_pop_uint8 (context_p);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_COMMA:
{
if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_RIGHT_PAREN:
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
if (stack_top == SCAN_STACK_PAREN_STATEMENT)
{
*mode = SCAN_MODE_STATEMENT;
}
else if (stack_top != SCAN_STACK_PAREN_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
parser_stack_pop_uint8 (context_p);
break;
}
case LEXER_SEMICOLON:
{
/* Needed by for (;;) statements. */
if (stack_top != SCAN_STACK_PAREN_STATEMENT)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
default:
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
}
return PARSER_FALSE;
} /* parser_scan_primary_expression */
/**
* Scan the tokens after the primary expression.
*
* @return PARSER_TRUE for break, PARSER_FALSE for fall through
*/
static int
parser_scan_post_primary_expression (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_DOT:
{
lexer_scan_identifier (context_p, PARSER_FALSE);
return PARSER_TRUE;
}
case LEXER_LEFT_PAREN:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_TRUE;
}
case LEXER_LEFT_SQUARE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_TRUE;
}
case LEXER_INCREASE:
case LEXER_DECREASE:
{
if (!context_p->token.was_newline)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return PARSER_TRUE;
}
/* FALLTHRU */
}
default:
{
break;
}
}
return PARSER_FALSE;
} /* parser_scan_post_primary_expression */
/**
* Scan the tokens after the primary expression.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
lexer_token_type_t end_type, /**< terminator token type */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_QUESTION_MARK:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_COMMA:
{
if (stack_top == SCAN_STACK_OBJECT_LITERAL)
{
*mode = SCAN_MODE_PROPERTY_NAME;
return PARSER_TRUE;
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_COLON:
{
if (stack_top == SCAN_STACK_COLON_EXPRESSION
|| stack_top == SCAN_STACK_COLON_STATEMENT)
{
if (stack_top == SCAN_STACK_COLON_EXPRESSION)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
}
else
{
*mode = SCAN_MODE_STATEMENT;
}
parser_stack_pop_uint8 (context_p);
return PARSER_FALSE;
}
/* FALLTHRU */
}
default:
{
break;
}
}
if (LEXER_IS_BINARY_OP_TOKEN (type)
|| (type == LEXER_SEMICOLON && stack_top == SCAN_STACK_PAREN_STATEMENT))
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
if ((type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
|| (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_EXPRESSION)
|| (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_OBJECT_LITERAL))
{
parser_stack_pop_uint8 (context_p);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
*mode = SCAN_MODE_STATEMENT;
if (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_STATEMENT)
{
parser_stack_pop_uint8 (context_p);
return PARSER_FALSE;
}
/* Check whether we can enter to statement mode. */
if (stack_top != SCAN_STACK_BLOCK_STATEMENT
&& stack_top != SCAN_STACK_BLOCK_EXPRESSION
&& !(stack_top == SCAN_STACK_HEAD && end_type == LEXER_SCAN_SWITCH))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
}
if (type == LEXER_RIGHT_BRACE
|| context_p->token.was_newline)
{
return PARSER_TRUE;
}
if (type != LEXER_SEMICOLON)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
}
return PARSER_FALSE;
} /* parser_scan_primary_expression_end */
/**
* Scan statements.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_statement (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_SEMICOLON:
case LEXER_KEYW_ELSE:
case LEXER_KEYW_DO:
case LEXER_KEYW_TRY:
case LEXER_KEYW_FINALLY:
case LEXER_KEYW_DEBUGGER:
{
return PARSER_FALSE;
}
case LEXER_KEYW_IF:
case LEXER_KEYW_WHILE:
case LEXER_KEYW_WITH:
case LEXER_KEYW_SWITCH:
case LEXER_KEYW_CATCH:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_KEYW_FOR:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
lexer_next_token (context_p);
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (context_p->token.type == LEXER_KEYW_VAR)
{
return PARSER_FALSE;
}
return PARSER_TRUE;
}
case LEXER_KEYW_VAR:
case LEXER_KEYW_THROW:
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_KEYW_RETURN:
{
lexer_next_token (context_p);
if (!context_p->token.was_newline
&& context_p->token.type != LEXER_SEMICOLON)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
}
return PARSER_TRUE;
}
case LEXER_KEYW_BREAK:
case LEXER_KEYW_CONTINUE:
{
lexer_next_token (context_p);
if (!context_p->token.was_newline
&& context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
return PARSER_FALSE;
}
return PARSER_TRUE;
}
case LEXER_KEYW_DEFAULT:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
return PARSER_FALSE;
}
case LEXER_KEYW_CASE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_RIGHT_BRACE:
{
if (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
|| stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
parser_stack_pop_uint8 (context_p);
if (stack_top == SCAN_STACK_BLOCK_EXPRESSION)
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
else if (stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA
&& context_p->token.type != LEXER_RIGHT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
}
return PARSER_TRUE;
}
return PARSER_FALSE;
}
break;
}
case LEXER_LEFT_BRACE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
return PARSER_FALSE;
}
case LEXER_KEYW_FUNCTION:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
*mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return PARSER_FALSE;
}
default:
{
break;
}
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_COLON)
{
*mode = SCAN_MODE_STATEMENT;
return PARSER_FALSE;
}
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
return PARSER_TRUE;
} /* parser_scan_statement */
/**
* Pre-scan for token(s).
*/
void
parser_scan_until (parser_context_t *context_p, /**< context */
lexer_range_t *range_p, /**< destination range */
lexer_token_type_t end_type) /**< terminator token type */
{
scan_modes_t mode;
lexer_token_type_t end_type_b = end_type;
range_p->source_p = context_p->source_p;
range_p->source_end_p = context_p->source_p;
range_p->line = context_p->line;
range_p->column = context_p->column;
mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (end_type == LEXER_KEYW_CASE)
{
end_type = LEXER_SCAN_SWITCH;
end_type_b = LEXER_SCAN_SWITCH;
mode = SCAN_MODE_STATEMENT;
}
else
{
lexer_next_token (context_p);
if (end_type == LEXER_KEYW_IN)
{
end_type_b = LEXER_SEMICOLON;
if (context_p->token.type == LEXER_KEYW_VAR)
{
lexer_next_token (context_p);
}
}
}
parser_stack_push_uint8 (context_p, SCAN_STACK_HEAD);
while (PARSER_TRUE)
{
lexer_token_type_t type = (lexer_token_type_t) context_p->token.type;
scan_stack_modes_t stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
if (type == LEXER_EOS)
{
parser_raise_error (context_p, PARSER_ERR_EXPRESSION_EXPECTED);
}
if (stack_top == SCAN_STACK_HEAD
&& (type == end_type || type == end_type_b))
{
parser_stack_pop_uint8 (context_p);
return;
}
switch (mode)
{
case SCAN_MODE_PRIMARY_EXPRESSION:
{
if (type == LEXER_ADD
|| type == LEXER_SUBTRACT
|| LEXER_IS_UNARY_OP_TOKEN (type))
{
break;
}
/* FALLTHRU */
}
case SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW:
{
if (parser_scan_primary_expression (context_p, type, stack_top, &mode))
{
continue;
}
break;
}
case SCAN_MODE_POST_PRIMARY_EXPRESSION:
{
if (parser_scan_post_primary_expression (context_p, type, &mode))
{
break;
}
/* FALLTHRU */
}
case SCAN_MODE_PRIMARY_EXPRESSION_END:
{
if (parser_scan_primary_expression_end (context_p, type, stack_top, end_type, &mode))
{
continue;
}
break;
}
case SCAN_MODE_STATEMENT:
{
if (end_type == LEXER_SCAN_SWITCH
&& stack_top == SCAN_STACK_HEAD
&& (type == LEXER_KEYW_DEFAULT || type == LEXER_KEYW_CASE || type == LEXER_RIGHT_BRACE))
{
parser_stack_pop_uint8 (context_p);
return;
}
if (parser_scan_statement (context_p, type, stack_top, &mode))
{
continue;
}
break;
}
case SCAN_MODE_FUNCTION_ARGUMENTS:
{
JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
}
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
while (PARSER_TRUE)
{
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
}
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
mode = SCAN_MODE_STATEMENT;
break;
}
case SCAN_MODE_PROPERTY_NAME:
{
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL);
lexer_scan_identifier (context_p, PARSER_TRUE);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
parser_stack_pop_uint8 (context_p);
mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
if (context_p->token.type == LEXER_PROPERTY_GETTER
|| context_p->token.type == LEXER_PROPERTY_SETTER)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
mode = SCAN_MODE_FUNCTION_ARGUMENTS;
break;
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
}
range_p->source_end_p = context_p->source_p;
lexer_next_token (context_p);
}
} /* parser_scan_until */
/**
* @}
* @}
* @}
*/
File diff suppressed because it is too large Load Diff
+942
View File
@@ -0,0 +1,942 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
/**********************************************************************/
/* Emitting byte codes */
/**********************************************************************/
/**
* Append two bytes to the cbc stream.
*/
static void
parser_emit_two_bytes (parser_context_t *context_p, /**< context */
uint8_t first_byte, /**< first byte */
uint8_t second_byte) /**< second byte */
{
uint32_t last_position = context_p->byte_code.last_position;
if (last_position + 2 <= PARSER_CBC_STREAM_PAGE_SIZE)
{
parser_mem_page_t *page_p = context_p->byte_code.last_p;
page_p->bytes[last_position] = first_byte;
page_p->bytes[last_position + 1] = second_byte;
context_p->byte_code.last_position = last_position + 2;
}
else if (last_position >= PARSER_CBC_STREAM_PAGE_SIZE)
{
parser_mem_page_t *page_p;
parser_cbc_stream_alloc_page (context_p, &context_p->byte_code);
page_p = context_p->byte_code.last_p;
page_p->bytes[0] = first_byte;
page_p->bytes[1] = second_byte;
context_p->byte_code.last_position = 2;
}
else
{
context_p->byte_code.last_p->bytes[PARSER_CBC_STREAM_PAGE_SIZE - 1] = first_byte;
parser_cbc_stream_alloc_page (context_p, &context_p->byte_code);
context_p->byte_code.last_p->bytes[0] = second_byte;
context_p->byte_code.last_position = 1;
}
} /* parser_emit_two_bytes */
#define PARSER_APPEND_TO_BYTE_CODE(context_p, byte) \
if ((context_p)->byte_code.last_position >= PARSER_CBC_STREAM_PAGE_SIZE) \
{ \
parser_cbc_stream_alloc_page ((context_p), &(context_p)->byte_code); \
} \
(context_p)->byte_code.last_p->bytes[(context_p)->byte_code.last_position++] = (uint8_t) (byte)
/**
* Append the current byte code to the stream
*/
void
parser_flush_cbc (parser_context_t *context_p) /**< context */
{
uint8_t flags;
if (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE)
{
return;
}
context_p->status_flags |= PARSER_NO_END_LABEL;
if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
{
cbc_opcode_t opcode = (cbc_opcode_t) context_p->last_cbc_opcode;
flags = cbc_flags[opcode];
PARSER_APPEND_TO_BYTE_CODE (context_p, opcode);
context_p->byte_code_size++;
}
else
{
cbc_ext_opcode_t opcode = (cbc_ext_opcode_t) PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode);
flags = cbc_ext_flags[opcode];
parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, opcode);
context_p->byte_code_size += 2;
}
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
{
uint16_t literal_index = context_p->last_cbc.literal_index;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
}
if (flags & CBC_HAS_LITERAL_ARG2)
{
uint16_t literal_index = context_p->last_cbc.value;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
if (!(flags & CBC_HAS_LITERAL_ARG))
{
literal_index = context_p->last_cbc.third_literal_index;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
}
}
if (flags & CBC_HAS_BYTE_ARG)
{
uint8_t byte_argument = (uint8_t) context_p->last_cbc.value;
JERRY_ASSERT (context_p->last_cbc.value <= CBC_MAXIMUM_BYTE_VALUE);
if (flags & CBC_POP_STACK_BYTE_ARG)
{
JERRY_ASSERT (context_p->stack_depth >= byte_argument);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, byte_argument);
}
PARSER_APPEND_TO_BYTE_CODE (context_p, byte_argument);
context_p->byte_code_size++;
}
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
const char *name_p;
if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
{
name_p = cbc_names[context_p->last_cbc_opcode];
}
else
{
name_p = cbc_ext_names[PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode)];
}
printf (" [%3d] %s", (int) context_p->stack_depth, name_p);
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
{
uint16_t literal_index = context_p->last_cbc.literal_index;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
}
if (flags & CBC_HAS_LITERAL_ARG2)
{
uint16_t literal_index = context_p->last_cbc.value;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
if (!(flags & CBC_HAS_LITERAL_ARG))
{
literal_index = context_p->last_cbc.third_literal_index;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
}
}
if (flags & CBC_HAS_BYTE_ARG)
{
printf (" byte_arg:%d", (int) context_p->last_cbc.value);
}
printf ("\n");
}
#endif /* PARSER_DUMP_BYTE_CODE */
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
} /* parser_flush_cbc */
/**
* Append a byte code
*/
void
parser_emit_cbc (parser_context_t *context_p, /**< context */
uint16_t opcode) /**< opcode */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, 0));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
} /* parser_emit_cbc */
/**
* Append a byte code with a literal argument
*/
void
parser_emit_cbc_literal (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
uint16_t literal_index) /**< literal index */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.literal_index = literal_index;
context_p->last_cbc.literal_type = LEXER_UNUSED_LITERAL;
context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY;
} /* parser_emit_cbc_literal */
/**
* Append a byte code with the current literal argument
*/
void
parser_emit_cbc_literal_from_token (parser_context_t *context_p, /**< context */
uint16_t opcode) /**< opcode */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.literal_index = context_p->lit_object.index;
context_p->last_cbc.literal_type = context_p->token.lit_location.type;
context_p->last_cbc.literal_object_type = context_p->lit_object.type;
} /* parser_emit_cbc_literal_from_token */
/**
* Append a byte code with a call argument
*/
void
parser_emit_cbc_call (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
size_t call_arguments) /**< number of arguments */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_BYTE_ARG));
JERRY_ASSERT (call_arguments <= CBC_MAXIMUM_BYTE_VALUE);
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.value = (uint16_t) call_arguments;
} /* parser_emit_cbc_call */
/**
* Append a push number 1/2 byte code
*/
void
parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */
int is_negative_number) /**< sign is negative */
{
uint16_t value = context_p->lit_object.index;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
JERRY_ASSERT (value < CBC_PUSH_NUMBER_1_RANGE_END);
JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (cbc_flags[CBC_PUSH_NUMBER_1]) == 1);
context_p->stack_depth++;
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
int real_value = value;
if (is_negative_number)
{
real_value = -real_value;
}
printf (" [%3d] %s number:%d\n", (int) context_p->stack_depth, cbc_names[CBC_PUSH_NUMBER_1], real_value);
}
#endif /* PARSER_DUMP_BYTE_CODE */
if (is_negative_number)
{
PARSER_PLUS_EQUAL_U16 (value, CBC_PUSH_NUMBER_1_RANGE_END);
}
parser_emit_two_bytes (context_p,
CBC_PUSH_NUMBER_1,
(uint8_t) value);
context_p->byte_code_size += 2;
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
} /* parser_emit_cbc_push_number */
/**
* Append a byte code with a branch argument
*/
void
parser_emit_cbc_forward_branch (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
parser_branch_t *branch_p) /**< branch result */
{
uint8_t flags;
uint32_t extra_byte_code_increase;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags |= PARSER_NO_END_LABEL;
if (PARSER_IS_BASIC_OPCODE (opcode))
{
flags = cbc_flags[opcode];
extra_byte_code_increase = 0;
}
else
{
PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);
flags = cbc_ext_flags[opcode];
extra_byte_code_increase = 1;
}
JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
JERRY_ASSERT (CBC_BRANCH_IS_FORWARD (flags));
JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);
/* Branch opcodes never push anything onto the stack. */
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
if (extra_byte_code_increase == 0)
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, cbc_names[opcode]);
}
else
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, cbc_ext_names[opcode]);
}
}
#endif /* PARSER_DUMP_BYTE_CODE */
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
opcode++;
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
PARSER_PLUS_EQUAL_U16 (opcode, 2);
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
parser_emit_two_bytes (context_p, (uint8_t) opcode, 0);
branch_p->page_p = context_p->byte_code.last_p;
branch_p->offset = (context_p->byte_code.last_position - 1) | (context_p->byte_code_size << 8);
context_p->byte_code_size += extra_byte_code_increase;
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
PARSER_APPEND_TO_BYTE_CODE (context_p, 0);
context_p->byte_code_size += 3;
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
parser_emit_two_bytes (context_p, 0, 0);
context_p->byte_code_size += 4;
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
} /* parser_emit_cbc_forward_branch */
/**
* Append a branch byte code and create an item
*/
parser_branch_node_t *
parser_emit_cbc_forward_branch_item (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
parser_branch_node_t *next_p) /**< next branch */
{
parser_branch_t branch;
parser_branch_node_t *new_item;
/* Since byte code insertion may throw an out-of-memory error,
* the branch is constructed locally, and copied later. */
parser_emit_cbc_forward_branch (context_p, opcode, &branch);
new_item = (parser_branch_node_t *) parser_malloc (context_p, sizeof (parser_branch_node_t));
new_item->branch = branch;
new_item->next_p = next_p;
return new_item;
} /* parser_emit_cbc_forward_branch_item */
/**
* Append a byte code with a branch argument
*/
void
parser_emit_cbc_backward_branch (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
uint32_t offset) /**< destination offset */
{
uint8_t flags;
#ifdef PARSER_DUMP_BYTE_CODE
const char *name;
#endif /* PARSER_DUMP_BYTE_CODE */
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags |= PARSER_NO_END_LABEL;
offset = context_p->byte_code_size - offset;
if (PARSER_IS_BASIC_OPCODE (opcode))
{
flags = cbc_flags[opcode];
#ifdef PARSER_DUMP_BYTE_CODE
name = cbc_names[opcode];
#endif /* PARSER_DUMP_BYTE_CODE */
}
else
{
PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);
flags = cbc_ext_flags[opcode];
context_p->byte_code_size++;
#ifdef PARSER_DUMP_BYTE_CODE
name = cbc_ext_names[opcode];
#endif /* PARSER_DUMP_BYTE_CODE */
}
JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
JERRY_ASSERT (CBC_BRANCH_IS_BACKWARD (flags));
JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);
JERRY_ASSERT (offset <= context_p->byte_code_size);
/* Branch opcodes never push anything onto the stack. */
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, name);
}
#endif /* PARSER_DUMP_BYTE_CODE */
context_p->byte_code_size += 2;
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
if (offset > 255)
{
opcode++;
context_p->byte_code_size++;
}
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
if (offset > 65535)
{
PARSER_PLUS_EQUAL_U16 (opcode, 2);
context_p->byte_code_size += 2;
}
else if (offset > 255)
{
opcode++;
context_p->byte_code_size++;
}
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
PARSER_APPEND_TO_BYTE_CODE (context_p, (uint8_t) opcode);
#if PARSER_MAXIMUM_CODE_SIZE > 65535
if (offset > 65535)
{
PARSER_APPEND_TO_BYTE_CODE (context_p, offset >> 16);
}
#endif /* PARSER_MAXIMUM_CODE_SIZE > 65535 */
if (offset > 255)
{
PARSER_APPEND_TO_BYTE_CODE (context_p, (offset >> 8) & 0xff);
}
PARSER_APPEND_TO_BYTE_CODE (context_p, offset & 0xff);
} /* parser_emit_cbc_backward_branch */
#undef PARSER_CHECK_LAST_POSITION
#undef PARSER_APPEND_TO_BYTE_CODE
/**
* Set a branch to the current byte code position
*/
void
parser_set_branch_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_t *branch_p) /**< branch result */
{
uint32_t delta;
size_t offset;
parser_mem_page_t *page_p = branch_p->page_p;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags &= ~PARSER_NO_END_LABEL;
JERRY_ASSERT (context_p->byte_code_size > (branch_p->offset >> 8));
delta = context_p->byte_code_size - (branch_p->offset >> 8);
offset = (branch_p->offset & CBC_LOWER_SEVEN_BIT_MASK);
JERRY_ASSERT (delta <= PARSER_MAXIMUM_CODE_SIZE);
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
page_p->bytes[offset++] = (uint8_t) (delta >> 8);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
#else
page_p->bytes[offset++] = (uint8_t) (delta >> 16);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
page_p->bytes[offset++] = (uint8_t) ((delta >> 8) & 0xff);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
#endif
page_p->bytes[offset++] = delta & 0xff;
} /* parser_set_branch_to_current_position */
/**
* Set breaks to the current byte code position
*/
void
parser_set_breaks_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_node_t *current_p) /**< branch list */
{
while (current_p != NULL)
{
parser_branch_node_t *next_p = current_p->next_p;
if (!(current_p->branch.offset & CBC_HIGHEST_BIT_MASK))
{
parser_set_branch_to_current_position (context_p, &current_p->branch);
}
parser_free (current_p);
current_p = next_p;
}
} /* parser_set_breaks_to_current_position */
/**
* Set continues to the current byte code position
*/
void
parser_set_continues_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_node_t *current_p) /**< branch list */
{
while (current_p != NULL)
{
if (current_p->branch.offset & CBC_HIGHEST_BIT_MASK)
{
parser_set_branch_to_current_position (context_p, &current_p->branch);
}
current_p = current_p->next_p;
}
} /* parser_set_continues_to_current_position */
/**
* Returns with the striong representation of the error
*/
const char *
parser_error_to_string (parser_error_t error) /**< error code */
{
switch (error)
{
case PARSER_ERR_OUT_OF_MEMORY:
{
return "Out of memory.";
}
case PARSER_ERR_LITERAL_LIMIT_REACHED:
{
return "Maximum number of literals reached.";
}
case PARSER_ERR_ARGUMENT_LIMIT_REACHED:
{
return "Maximum number of function arguments reached.";
}
case PARSER_ERR_STACK_LIMIT_REACHED:
{
return "Maximum function stack size reached.";
}
case PARSER_ERR_REGISTER_LIMIT_REACHED:
{
return "Maximum number of registers is reached.";
}
case PARSER_ERR_INVALID_CHARACTER:
{
return "Invalid (unexpected) character.";
}
case PARSER_ERR_INVALID_HEX_DIGIT:
{
return "Invalid hexadecimal digit.";
}
case PARSER_ERR_INVALID_ESCAPE_SEQUENCE:
{
return "Invalid escape sequence.";
}
case PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE:
{
return "Invalid unicode escape sequence.";
}
case PARSER_ERR_INVALID_IDENTIFIER_START:
{
return "Character cannot be start of an identifier.";
}
case PARSER_ERR_INVALID_IDENTIFIER_PART:
{
return "Character cannot be part of an identifier.";
}
case PARSER_ERR_INVALID_NUMBER:
{
return "Invalid number.";
}
case PARSER_ERR_MISSING_EXPONENT:
{
return "Missing exponent part.";
}
case PARSER_ERR_IDENTIFIER_AFTER_NUMBER:
{
return "Identifier cannot start after a number.";
}
case PARSER_ERR_INVALID_REGEXP:
{
return "Invalid regular expression.";
}
case PARSER_ERR_UNKNOWN_REGEXP_FLAG:
{
return "Unknown regexp flag.";
}
case PARSER_ERR_DUPLICATED_REGEXP_FLAG:
{
return "Duplicated regexp flag.";
}
case PARSER_ERR_UNSUPPORTED_REGEXP:
{
return "Regexp is not supported in compact profile.";
}
case PARSER_ERR_IDENTIFIER_TOO_LONG:
{
return "Identifier is too long.";
}
case PARSER_ERR_STRING_TOO_LONG:
{
return "String is too long.";
}
case PARSER_ERR_NUMBER_TOO_LONG:
{
return "Number too long.";
}
case PARSER_ERR_REGEXP_TOO_LONG:
{
return "Regexp too long.";
}
case PARSER_ERR_UNTERMINATED_MULTILINE_COMMENT:
{
return "Unterminated multiline comment.";
}
case PARSER_ERR_UNTERMINATED_STRING:
{
return "Unterminated string literal.";
}
case PARSER_ERR_UNTERMINATED_REGEXP:
{
return "Unterminated regexp literal.";
}
case PARSER_ERR_NEWLINE_NOT_ALLOWED:
{
return "Newline is not allowed in strings or regexps.";
}
case PARSER_ERR_OCTAL_NUMBER_NOT_ALLOWED:
{
return "Octal numbers are not allowed in strict mode.";
}
case PARSER_ERR_OCTAL_ESCAPE_NOT_ALLOWED:
{
return "Octal escape sequences are not allowed in strict mode.";
}
case PARSER_ERR_STRICT_IDENT_NOT_ALLOWED:
{
return "Identifier name is reserved in strict mode.";
}
case PARSER_ERR_EVAL_NOT_ALLOWED:
{
return "Eval is not allowed to use here in strict mode.";
}
case PARSER_ERR_ARGUMENTS_NOT_ALLOWED:
{
return "Arguments is not allowed to use here in strict mode.";
}
case PARSER_ERR_DELETE_IDENT_NOT_ALLOWED:
{
return "Deleting identifier is not allowed in strict mode.";
}
case PARSER_ERR_EVAL_CANNOT_ASSIGNED:
{
return "Eval cannot assigned in strict mode.";
}
case PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED:
{
return "Arguments cannot assigned in strict mode.";
}
case PARSER_ERR_WITH_NOT_ALLOWED:
{
return "With statement not allowed in strict mode.";
}
case PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED:
{
return "Multiple default cases not allowed.";
}
case PARSER_ERR_DEFAULT_NOT_IN_SWITCH:
{
return "Default statement must be in a switch block.";
}
case PARSER_ERR_CASE_NOT_IN_SWITCH:
{
return "Case statement must be in a switch block.";
}
case PARSER_ERR_LEFT_PAREN_EXPECTED:
{
return "Expected '(' token.";
}
case PARSER_ERR_LEFT_BRACE_EXPECTED:
{
return "Expected '{' token.";
}
case PARSER_ERR_RIGHT_PAREN_EXPECTED:
{
return "Expected ')' token.";
}
case PARSER_ERR_RIGHT_SQUARE_EXPECTED:
{
return "Expected ']' token.";
}
case PARSER_ERR_COLON_EXPECTED:
{
return "Expected ':' token.";
}
case PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED:
{
return "Expected ':' token for ?: conditional expression.";
}
case PARSER_ERR_SEMICOLON_EXPECTED:
{
return "Expected ';' token.";
}
case PARSER_ERR_IN_EXPECTED:
{
return "Expected 'in' token.";
}
case PARSER_ERR_WHILE_EXPECTED:
{
return "While expected for do-while loop.";
}
case PARSER_ERR_CATCH_FINALLY_EXPECTED:
{
return "Catch or finally block expected.";
}
case PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED:
{
return "Expected ',' or ']' after an array item.";
}
case PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED:
{
return "Expected ',' or '}' after a property definition.";
}
case PARSER_ERR_IDENTIFIER_EXPECTED:
{
return "Identifier expected.";
}
case PARSER_ERR_EXPRESSION_EXPECTED:
{
return "Expression expected.";
}
case PARSER_ERR_PRIMARY_EXP_EXPECTED:
{
return "Primary expression expected.";
}
case PARSER_ERR_STATEMENT_EXPECTED:
{
return "Statement expected.";
}
case PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED:
{
return "Property identifier expected.";
}
case PARSER_ERR_ARGUMENT_LIST_EXPECTED:
{
return "Expected argument list.";
}
case PARSER_ERR_NO_ARGUMENTS_EXPECTED:
{
return "Property getters must have no arguments.";
}
case PARSER_ERR_ONE_ARGUMENT_EXPECTED:
{
return "Property setters must have one argument.";
}
case PARSER_ERR_INVALID_EXPRESSION:
{
return "Invalid expression.";
}
case PARSER_ERR_INVALID_SWITCH:
{
return "Invalid switch body.";
}
case PARSER_ERR_INVALID_BREAK:
{
return "Break statement must be inside a loop or switch.";
}
case PARSER_ERR_INVALID_BREAK_LABEL:
{
return "Labelled statement targeted by a break not found.";
}
case PARSER_ERR_INVALID_CONTINUE:
{
return "Continue statement must be inside a loop.";
}
case PARSER_ERR_INVALID_CONTINUE_LABEL:
{
return "Labelled statement targeted by a continue noty found.";
}
case PARSER_ERR_INVALID_RETURN:
{
return "Return statement must be inside a function body.";
}
case PARSER_ERR_INVALID_RIGHT_SQUARE:
{
return "Unexpected '}' token.";
}
case PARSER_ERR_DUPLICATED_LABEL:
{
return "Duplicated label.";
}
case PARSER_ERR_OBJECT_PROPERTY_REDEFINED:
{
return "Property of object literal redefined.";
}
case PARSER_ERR_NON_STRICT_ARG_DEFINITION:
{
return "Non strict argument definition.";
}
default:
{
break;
}
}
JERRY_ASSERT (error == PARSER_ERR_NO_ERROR);
return "No error.";
} /* parser_error_to_string */
/**
* @}
* @}
* @}
*/
File diff suppressed because it is too large Load Diff
+143
View File
@@ -0,0 +1,143 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef JS_PARSER_H
#define JS_PARSER_H
#include "byte-code.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_parser Parser
* @{
*/
/**
* Error codes.
*/
typedef enum
{
PARSER_ERR_NO_ERROR, /**< no error */
PARSER_ERR_OUT_OF_MEMORY, /**< out of memory */
PARSER_ERR_LITERAL_LIMIT_REACHED, /**< maximum number of literals reached */
PARSER_ERR_ARGUMENT_LIMIT_REACHED, /**< maximum number of function arguments reached */
PARSER_ERR_STACK_LIMIT_REACHED, /**< maximum function stack size reached */
PARSER_ERR_REGISTER_LIMIT_REACHED, /**< maximum register size reached */
PARSER_ERR_INVALID_CHARACTER, /**< unexpected character */
PARSER_ERR_INVALID_HEX_DIGIT, /**< invalid hexadecimal digit */
PARSER_ERR_INVALID_ESCAPE_SEQUENCE, /**< invalid escape sequence */
PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE, /**< invalid unicode escape sequence */
PARSER_ERR_INVALID_IDENTIFIER_START, /**< character cannot be start of an identifier */
PARSER_ERR_INVALID_IDENTIFIER_PART, /**< character cannot be part of an identifier */
PARSER_ERR_INVALID_NUMBER, /**< invalid number literal */
PARSER_ERR_MISSING_EXPONENT, /**< missing exponent */
PARSER_ERR_IDENTIFIER_AFTER_NUMBER, /**< identifier start after number */
PARSER_ERR_INVALID_REGEXP, /**< invalid regular expression */
PARSER_ERR_UNKNOWN_REGEXP_FLAG, /**< unknown regexp flag */
PARSER_ERR_DUPLICATED_REGEXP_FLAG, /**< duplicated regexp flag */
PARSER_ERR_UNSUPPORTED_REGEXP, /**< regular expression is not supported in compact profile */
PARSER_ERR_IDENTIFIER_TOO_LONG, /**< too long identifier */
PARSER_ERR_STRING_TOO_LONG, /**< too long string literal */
PARSER_ERR_NUMBER_TOO_LONG, /**< too long number literal */
PARSER_ERR_REGEXP_TOO_LONG, /**< too long regexp literal */
PARSER_ERR_UNTERMINATED_MULTILINE_COMMENT, /**< unterminated multiline comment */
PARSER_ERR_UNTERMINATED_STRING, /**< unterminated string literal */
PARSER_ERR_UNTERMINATED_REGEXP, /**< unterminated regexp literal */
PARSER_ERR_NEWLINE_NOT_ALLOWED, /**< newline is not allowed */
PARSER_ERR_OCTAL_NUMBER_NOT_ALLOWED, /**< octal numbers are not allowed in strict mode */
PARSER_ERR_OCTAL_ESCAPE_NOT_ALLOWED, /**< octal escape sequences are not allowed in strict mode */
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 */
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 */
PARSER_ERR_WITH_NOT_ALLOWED, /**< with statement is not allowed in strict mode */
PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED, /**< multiple default cases are not allowed */
PARSER_ERR_DEFAULT_NOT_IN_SWITCH, /**< default statement is not in switch block */
PARSER_ERR_CASE_NOT_IN_SWITCH, /**< case statement is not in switch block */
PARSER_ERR_LEFT_PAREN_EXPECTED, /**< left paren expected */
PARSER_ERR_LEFT_BRACE_EXPECTED, /**< left brace expected */
PARSER_ERR_RIGHT_PAREN_EXPECTED, /**< right paren expected */
PARSER_ERR_RIGHT_SQUARE_EXPECTED, /**< right square expected */
PARSER_ERR_COLON_EXPECTED, /**< colon expected */
PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED, /**< colon expected for conditional expression */
PARSER_ERR_SEMICOLON_EXPECTED, /**< semicolon expected */
PARSER_ERR_IN_EXPECTED, /**< in keyword expected */
PARSER_ERR_WHILE_EXPECTED, /**< while expected for do-while loop */
PARSER_ERR_CATCH_FINALLY_EXPECTED, /**< catch or finally expected */
PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED, /**< array item separator expected */
PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED, /**< object item separator expected */
PARSER_ERR_IDENTIFIER_EXPECTED, /**< identifier expected */
PARSER_ERR_EXPRESSION_EXPECTED, /**< expression expected */
PARSER_ERR_PRIMARY_EXP_EXPECTED, /**< primary expression expected */
PARSER_ERR_STATEMENT_EXPECTED, /**< statement expected */
PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED, /**< property identifier expected */
PARSER_ERR_ARGUMENT_LIST_EXPECTED, /**< argument list expected */
PARSER_ERR_NO_ARGUMENTS_EXPECTED, /**< property getters must have no arguments */
PARSER_ERR_ONE_ARGUMENT_EXPECTED, /**< property setters must have one argument */
PARSER_ERR_INVALID_EXPRESSION, /**< invalid expression */
PARSER_ERR_INVALID_SWITCH, /**< invalid switch body */
PARSER_ERR_INVALID_BREAK, /**< break must be inside a loop or switch */
PARSER_ERR_INVALID_BREAK_LABEL, /**< break target not found */
PARSER_ERR_INVALID_CONTINUE, /**< continue must be inside a loop */
PARSER_ERR_INVALID_CONTINUE_LABEL, /**< continue target not found */
PARSER_ERR_INVALID_RETURN, /**< return must be inside a function */
PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */
PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */
PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */
PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */
} parser_error_t;
/* Source code line counter type. */
typedef uint32_t parser_line_counter_t;
/**
* Error code location.
*/
typedef struct
{
parser_error_t error; /**< error code */
parser_line_counter_t line; /**< line where the error occured */
parser_line_counter_t column; /**< column where the error occured */
} parser_error_location;
/* Note: source must be a valid UTF-8 string. */
ecma_compiled_code_t * parser_parse_script (const uint8_t *, size_t, int, parser_error_location *);
const char *parser_error_to_string (parser_error_t);
extern void parser_set_show_instrs (int);
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_H */
-255
View File
@@ -1,255 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "jsp-early-error.h"
#include "stack.h"
#include "jrt.h"
#include "parser.h"
#include "jrt-libc-includes.h"
#include "ecma-helpers.h"
#include "lit-magic-strings.h"
/**
* Early error longjmp label, used to finish parse upon an early error occurence
*
* See also:
* jsp_early_error_get_early_error_longjmp_label
* jsp_early_error_raise_error
*/
static jmp_buf jsp_early_error_label;
/**
* Type of early error occured, or JSP_EARLY_ERROR__NO_ERROR
*/
jsp_early_error_t jsp_early_error_type;
typedef struct
{
prop_type type;
lit_literal_t lit;
} prop_literal;
enum
{
props_global_size
};
STATIC_STACK (props, prop_literal)
enum
{
size_t_stack_global_size
};
STATIC_STACK (size_t_stack, size_t)
/**
* Get buffer for SyntaxError longjmp label
*
* @return pointer to jmp_buf
*/
jmp_buf *
jsp_early_error_get_early_error_longjmp_label (void)
{
return &jsp_early_error_label;
} /* jsp_early_error_get_early_error_longjmp_label */
/**
* Raise an early error of specified type
*
* Note:
* Performs longjmp to early error longjmp label
*
* See also:
* parser_parse_program
*/
void __attribute__((noreturn))
jsp_early_error_raise_error (jsp_early_error_t type) /**< type of error to raise */
{
JERRY_ASSERT (jsp_early_error_type == JSP_EARLY_ERROR__NO_ERROR);
jsp_early_error_type = type;
longjmp (jsp_early_error_label, 1);
} /* jsp_early_error_raise_error */
/**
* Get type of occured early error
*
* @return type
*/
jsp_early_error_t
jsp_early_error_get_type (void)
{
JERRY_ASSERT (jsp_early_error_type != JSP_EARLY_ERROR__NO_ERROR);
return jsp_early_error_type;
} /* jsp_early_error_get_type */
static prop_literal
create_prop_literal (lit_literal_t lit, prop_type type)
{
prop_literal ret;
ret.type = type;
ret.lit = lit;
return ret;
}
void
jsp_early_error_start_checking_of_prop_names (void)
{
STACK_PUSH (size_t_stack, STACK_SIZE (props));
}
void
jsp_early_error_add_prop_name (jsp_operand_t op, prop_type pt)
{
JERRY_ASSERT (jsp_is_string_lit_operand (op));
STACK_PUSH (props, create_prop_literal (lit_get_literal_by_cp (jsp_operand_get_literal (op)), pt));
}
void
jsp_early_error_check_for_duplication_of_prop_names (bool is_strict, locus loc __attr_unused___)
{
if (STACK_SIZE (props) - STACK_TOP (size_t_stack) < 2)
{
STACK_DROP (props, (size_t) (STACK_SIZE (props) - STACK_TOP (size_t_stack)));
STACK_DROP (size_t_stack, 1);
return;
}
for (size_t i = (STACK_TOP (size_t_stack) + 1);
i < STACK_SIZE (props);
i++)
{
const prop_literal previous = STACK_ELEMENT (props, i);
JERRY_ASSERT (previous.type == PROP_DATA
|| previous.type == PROP_GET
|| previous.type == PROP_SET);
for (size_t j = STACK_TOP (size_t_stack); j < i; j = j + 1)
{
/*4*/
const prop_literal current = STACK_ELEMENT (props, j);
JERRY_ASSERT (current.type == PROP_DATA
|| current.type == PROP_GET
|| current.type == PROP_SET);
if (lit_literal_equal (previous.lit, current.lit))
{
/*a*/
if (is_strict && previous.type == PROP_DATA && current.type == PROP_DATA)
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*b*/
if (previous.type == PROP_DATA
&& (current.type == PROP_SET || current.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*c*/
if (current.type == PROP_DATA
&& (previous.type == PROP_SET || previous.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*d*/
if ((previous.type == PROP_SET && current.type == PROP_SET)
|| (previous.type == PROP_GET && current.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be accessor of same type",
loc, lit_literal_to_str_internal_buf (current.lit));
}
}
}
}
STACK_DROP (props, (size_t) (STACK_SIZE (props) - STACK_TOP (size_t_stack)));
STACK_DROP (size_t_stack, 1);
}
void
jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t lit, /**< literal to check */
locus loc) /**< location of the literal in source code */
{
if (lit_literal_equal_type_utf8 (lit,
lit_get_magic_string_utf8 (LIT_MAGIC_STRING_ARGUMENTS),
lit_get_magic_string_size (LIT_MAGIC_STRING_ARGUMENTS))
|| lit_literal_equal_type_utf8 (lit,
lit_get_magic_string_utf8 (LIT_MAGIC_STRING_EVAL),
lit_get_magic_string_size (LIT_MAGIC_STRING_EVAL)))
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "'eval' and 'arguments' are not allowed here in strict mode", loc);
}
}
void
jsp_early_error_check_for_eval_and_arguments_in_strict_mode (jsp_operand_t op, bool is_strict, locus loc)
{
if (is_strict)
{
lit_cpointer_t lit_cp;
if (jsp_is_string_lit_operand (op)
|| jsp_is_number_lit_operand (op))
{
lit_cp = jsp_operand_get_literal (op);
}
else if (jsp_is_identifier_operand (op))
{
lit_cp = jsp_operand_get_identifier_name (op);
}
else
{
return;
}
jsp_early_error_emit_error_on_eval_and_arguments (lit_get_literal_by_cp (lit_cp), loc);
}
}
void
jsp_early_error_check_delete (bool is_strict, locus loc __attr_unused___)
{
if (is_strict)
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "'delete' operator shall not apply on identifier in strict mode.", loc);
}
}
void
jsp_early_error_init (void)
{
jsp_early_error_type = JSP_EARLY_ERROR__NO_ERROR;
STACK_INIT (props);
STACK_INIT (size_t_stack);
}
void
jsp_early_error_free (void)
{
STACK_FREE (size_t_stack);
STACK_FREE (props);
}
-90
View File
@@ -1,90 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef JSP_EARLY_ERROR_H
#define JSP_EARLY_ERROR_H
#include "jrt-libc-includes.h"
#include "lexer.h"
#include "opcodes-dumper.h"
#ifndef JERRY_NDEBUG
#define PARSE_ERROR_PRINT_PLACE(TYPE, LOCUS) do { \
size_t line, column; \
lexer_locus_to_line_and_column ((LOCUS), &line, &column); \
lexer_dump_line (line); \
printf ("\n"); \
for (size_t i = 0; i < column; i++) { \
jerry_port_putchar (' '); \
} \
printf ("^\n"); \
printf ("%s: Ln %lu, Col %lu: ", TYPE, (unsigned long) (line + 1), (unsigned long) (column + 1)); \
} while (0)
#define PARSE_ERROR(type, MESSAGE, LOCUS) do { \
locus __loc = LOCUS; \
PARSE_ERROR_PRINT_PLACE ("ERROR", __loc); \
printf ("%s\n", MESSAGE); \
jsp_early_error_raise_error (type); \
} while (0)
#define PARSE_ERROR_VARG(type, MESSAGE, LOCUS, ...) do { \
locus __loc = LOCUS; \
PARSE_ERROR_PRINT_PLACE ("ERROR", __loc); \
printf (MESSAGE, __VA_ARGS__); \
printf ("\n"); \
jsp_early_error_raise_error (type); \
} while (0)
#else /* JERRY_NDEBUG */
#define PARSE_ERROR(type, MESSAGE, LOCUS) do { \
locus __attr_unused___ unused_value = LOCUS; jsp_early_error_raise_error (type); \
} while (0)
#define PARSE_ERROR_VARG(type, MESSAGE, LOCUS, ...) do { \
locus __attr_unused___ unused_value = LOCUS; jsp_early_error_raise_error (type); \
} while (0)
#endif /* JERRY_NDEBUG */
typedef enum __attr_packed___
{
PROP_DATA,
PROP_SET,
PROP_GET
} prop_type;
/**
* Early error types (ECMA-262 v5, 16)
*/
typedef enum
{
JSP_EARLY_ERROR__NO_ERROR, /** initializer value (indicates that no error occured) */
JSP_EARLY_ERROR_SYNTAX, /**< SyntaxError */
JSP_EARLY_ERROR_REFERENCE /**< ReferenceError */
} jsp_early_error_t;
void jsp_early_error_init (void);
void jsp_early_error_free (void);
void jsp_early_error_start_checking_of_prop_names (void);
void jsp_early_error_add_prop_name (jsp_operand_t, prop_type);
void jsp_early_error_check_for_duplication_of_prop_names (bool, locus);
void jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t, locus);
void jsp_early_error_check_for_eval_and_arguments_in_strict_mode (jsp_operand_t, bool, locus);
void jsp_early_error_check_delete (bool, locus);
jmp_buf *jsp_early_error_get_early_error_longjmp_label (void);
void __attribute__((noreturn)) jsp_early_error_raise_error (jsp_early_error_t);
jsp_early_error_t jsp_early_error_get_type (void);
#endif /* JSP_EARLY_ERROR_H */
-122
View File
@@ -1,122 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef JSP_INTERNAL_H
#define JSP_INTERNAL_H
#include "scopes-tree.h"
/**
* Parse stage
*/
typedef enum
{
PREPARSE, /**< preparse stage */
DUMP /**< dump stage */
} jsp_parse_mode_t;
/**
* Size of the temporary literal set
*/
#define SCOPE_TMP_LIT_SET_SIZE 32
/**
* Parser context
*/
typedef struct
{
struct jsp_state_t *state_stack_p; /**< parser stack */
jsp_parse_mode_t mode; /**< parse stage */
scope_type_t scope_type; /**< type of currently parsed scope */
uint16_t processed_child_scopes_counter; /**< number of processed
* child scopes of the
* current scope */
union
{
/**
* Preparse stage information
*/
struct
{
/**
* Currently parsed scope
*/
scopes_tree current_scope_p;
/**
* Container of the temporary literal set
*
* Temporary literal set is used for estimation of number of unique literals
* in a byte-code instructions block (BLOCK_SIZE). The calculated number
* is always equal or larger than actual number of unique literals.
*
* The set is emptied upon:
* - reaching a bytecode block border;
* - changing scope, to which instructions are dumped.
*
* Emptying the set in second case is necessary, as the set should contain
* unique literals of a bytecode block, and, upon switching to another scope,
* current bytecode block is also switched, correspondingly. However, this
* could only lead to overestimation of unique literals number, relatively
* to the actual number.
*/
lit_cpointer_t tmp_lit_set[SCOPE_TMP_LIT_SET_SIZE];
/**
* Number of items in the temporary literal set
*/
uint8_t tmp_lit_set_num;
} preparse_stage;
/**
* Dump stage information
*/
struct
{
/**
* Current scope's byte-code header
*/
bytecode_data_header_t *current_bc_header_p;
/**
* Pointer to the scope that would be parsed next
*/
scopes_tree next_scope_to_dump_p;
} dump_stage;
} u;
} jsp_ctx_t;
void jsp_init_ctx (jsp_ctx_t *, scope_type_t);
bool jsp_is_dump_mode (jsp_ctx_t *);
void jsp_switch_to_dump_mode (jsp_ctx_t *, scopes_tree);
bool jsp_is_strict_mode (jsp_ctx_t *);
void jsp_set_strict_mode (jsp_ctx_t *);
scope_type_t jsp_get_scope_type (jsp_ctx_t *);
void jsp_set_scope_type (jsp_ctx_t *, scope_type_t);
uint16_t jsp_get_processed_child_scopes_counter (jsp_ctx_t *);
void jsp_set_processed_child_scopes_counter (jsp_ctx_t *, uint16_t);
uint16_t jsp_get_and_inc_processed_child_scopes_counter (jsp_ctx_t *);
scopes_tree jsp_get_next_scopes_tree_node_to_dump (jsp_ctx_t *);
scopes_tree jsp_get_current_scopes_tree_node (jsp_ctx_t *);
void jsp_set_current_scopes_tree_node (jsp_ctx_t *, scopes_tree);
bytecode_data_header_t *jsp_get_current_bytecode_header (jsp_ctx_t *);
void jsp_set_current_bytecode_header (jsp_ctx_t *, bytecode_data_header_t *);
void jsp_empty_tmp_literal_set (jsp_ctx_t *);
void jsp_account_next_bytecode_to_literal_reference (jsp_ctx_t *, lit_cpointer_t);
#endif /* !JSP_INTERNAL_H */
-170
View File
@@ -1,170 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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 "jrt.h"
#include "jsp-mm.h"
#include "mem-allocator.h"
#include "mem-heap.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup managedmem Managed memory allocation
* @{
*/
/**
* Header of a managed block, allocated by parser
*/
typedef struct
{
mem_cpointer_t prev_block_cp; /**< previous managed block */
mem_cpointer_t next_block_cp; /**< next managed block */
uint32_t padding; /**< padding for alignment */
} jsp_mm_header_t;
/**
* Check that alignment of jsp_mm_header_t is MEM_ALIGNMENT
*/
JERRY_STATIC_ASSERT ((sizeof (jsp_mm_header_t) % MEM_ALIGNMENT) == 0);
/**
* List used for tracking memory blocks
*/
jsp_mm_header_t *jsp_mm_blocks_p = NULL;
/**
* Initialize managed memory allocator
*/
void
jsp_mm_init (void)
{
JERRY_ASSERT (jsp_mm_blocks_p == NULL);
} /* jsp_mm_init */
/**
* Finalize managed memory allocator
*/
void
jsp_mm_finalize (void)
{
JERRY_ASSERT (jsp_mm_blocks_p == NULL);
} /* jsp_mm_finalize */
/**
* Recommend allocation size
*
* Note:
* The interface is used by collection allocators
* for storage of data that takes the specified
* amount of bytes upon allocation, but probably
* would require more.
*
* To reduce probability of reallocation in future,
* the allocators can request more space in first
* allocation request.
*
* The interface helps to choose appropriate space
* to allocate, considering amount of heap space,
* that would be waste if allocation size
* would not be increased.
*
* @return recommended allocation size
*/
size_t
jsp_mm_recommend_size (size_t minimum_size) /**< minimum required size */
{
size_t block_and_header_size = mem_heap_recommend_allocation_size (minimum_size + sizeof (jsp_mm_header_t));
return block_and_header_size - sizeof (jsp_mm_header_t);
} /* jsp_mm_recommend_size */
/**
* Allocate a managed memory block of specified size
*
* @return pointer to data space of allocated block
*/
void*
jsp_mm_alloc (size_t size) /**< size of block to allocate */
{
void *ptr_p = mem_heap_alloc_block (size + sizeof (jsp_mm_header_t), MEM_HEAP_ALLOC_SHORT_TERM);
jsp_mm_header_t *tmem_header_p = (jsp_mm_header_t*) ptr_p;
tmem_header_p->prev_block_cp = MEM_CP_NULL;
MEM_CP_SET_POINTER (tmem_header_p->next_block_cp, jsp_mm_blocks_p);
if (jsp_mm_blocks_p != NULL)
{
MEM_CP_SET_POINTER (jsp_mm_blocks_p->prev_block_cp, tmem_header_p);
}
jsp_mm_blocks_p = tmem_header_p;
return (void *) (tmem_header_p + 1);
} /* jsp_mm_alloc */
/**
* Free a managed memory block
*/
void
jsp_mm_free (void *ptr) /**< pointer to data space of allocated block */
{
jsp_mm_header_t *tmem_header_p = ((jsp_mm_header_t *) ptr) - 1;
jsp_mm_header_t *prev_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
tmem_header_p->prev_block_cp);
jsp_mm_header_t *next_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
tmem_header_p->next_block_cp);
if (prev_block_p != NULL)
{
prev_block_p->next_block_cp = tmem_header_p->next_block_cp;
}
else
{
JERRY_ASSERT (jsp_mm_blocks_p == tmem_header_p);
jsp_mm_blocks_p = next_block_p;
}
if (next_block_p != NULL)
{
next_block_p->prev_block_cp = tmem_header_p->prev_block_cp;
}
mem_heap_free_block (tmem_header_p);
} /* jsp_mm_free */
/**
* Free all currently allocated managed memory blocks
*/
void
jsp_mm_free_all (void)
{
while (jsp_mm_blocks_p != NULL)
{
jsp_mm_header_t *next_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
jsp_mm_blocks_p->next_block_cp);
mem_heap_free_block (jsp_mm_blocks_p);
jsp_mm_blocks_p = next_block_p;
}
} /* jsp_mm_free_all */
/**
* @}
* @}
*/
-40
View File
@@ -1,40 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef JSP_MM_H
#define JSP_MM_H
#include "jrt-libc-includes.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup managedmem Managed memory allocation
* @{
*/
extern void jsp_mm_init (void);
extern void jsp_mm_finalize (void);
extern size_t jsp_mm_recommend_size (size_t);
extern void *jsp_mm_alloc (size_t);
extern void jsp_mm_free (void *);
extern void jsp_mm_free_all (void);
/**
* @}
* @}
*/
#endif /* !JSP_MM_H */
File diff suppressed because it is too large Load Diff
-282
View File
@@ -1,282 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef LEXER_H
#define LEXER_H
#include "lit-literal.h"
#include "lit-strings.h"
#define INVALID_LITERAL (rcs_cpointer_null_cp ())
/* Keywords. */
typedef enum __attr_packed___
{
/* Not a keyword. */
KW_BREAK,
KW_CASE,
KW_CATCH,
KW_CLASS,
KW_CONST,
KW_CONTINUE,
KW_DEBUGGER,
KW_DEFAULT,
KW_DELETE,
KW_DO,
KW_ELSE,
KW_ENUM,
KW_EXPORT,
KW_EXTENDS,
KW_FINALLY,
KW_FOR,
KW_FUNCTION,
KW_IF,
KW_IN,
KW_INSTANCEOF,
KW_INTERFACE,
KW_IMPORT,
KW_IMPLEMENTS,
KW_LET,
KW_NEW,
KW_PACKAGE,
KW_PRIVATE,
KW_PROTECTED,
KW_PUBLIC,
KW_RETURN,
KW_STATIC,
KW_SUPER,
KW_SWITCH,
KW_THIS,
KW_THROW,
KW_TRY,
KW_TYPEOF,
KW_VAR,
KW_VOID,
KW_WHILE,
KW_WITH,
KW_YIELD
} keyword;
/* Type of tokens. */
typedef enum __attr_packed___
{
TOKEN_TYPE__BEGIN = 1,
TOK_EOF = TOKEN_TYPE__BEGIN, // End of file
TOK_NAME, // Identifier
TOK_SMALL_INT,
TOK_NUMBER,
TOK_NULL,
TOK_BOOL,
TOK_STRING,
TOK_OPEN_BRACE, // {
TOK_CLOSE_BRACE, // }
TOK_OPEN_PAREN, // (
TOK_CLOSE_PAREN, //)
TOK_OPEN_SQUARE, // [
TOK_CLOSE_SQUARE, // ]
TOK_DOT, // .
TOK_SEMICOLON, // ;
TOK_COMMA, // ,
TOKEN_TYPE__UNARY_BEGIN,
TOKEN_TYPE__ADDITIVE_BEGIN = TOKEN_TYPE__UNARY_BEGIN,
TOK_PLUS = TOKEN_TYPE__ADDITIVE_BEGIN, // +
TOK_MINUS, // -
TOKEN_TYPE__ADDITIVE_END = TOK_MINUS,
TOK_DOUBLE_PLUS, // ++
TOK_DOUBLE_MINUS, // --
TOK_NOT, // !
TOK_COMPL, // ~
TOKEN_TYPE__UNARY_END = TOK_COMPL, /* keywords are not listed
* in the range */
TOKEN_TYPE__MULTIPLICATIVE_BEGIN,
TOK_MULT = TOKEN_TYPE__MULTIPLICATIVE_BEGIN, // *
TOK_MOD, // %
TOK_DIV, // /
TOKEN_TYPE__MULTIPLICATIVE_END = TOK_DIV,
TOKEN_TYPE__SHIFT_BEGIN,
TOK_LSHIFT = TOKEN_TYPE__SHIFT_BEGIN, // <<
TOK_RSHIFT, // >>
TOK_RSHIFT_EX, // >>>
TOKEN_TYPE__SHIFT_END = TOK_RSHIFT_EX,
TOKEN_TYPE__RELATIONAL_BEGIN,
TOK_LESS = TOKEN_TYPE__RELATIONAL_BEGIN, // <
TOK_GREATER, // >
TOK_LESS_EQ, // <=
TOK_GREATER_EQ, // <=
TOKEN_TYPE__RELATIONAL_END = TOK_GREATER_EQ,
TOKEN_TYPE__EQUALITY_BEGIN,
TOK_DOUBLE_EQ = TOKEN_TYPE__EQUALITY_BEGIN, // ==
TOK_NOT_EQ, // !=
TOK_TRIPLE_EQ, // ===
TOK_NOT_DOUBLE_EQ, // !==
TOKEN_TYPE__EQUALITY_END = TOK_NOT_DOUBLE_EQ,
TOK_AND, // &
TOK_OR, // |
TOK_XOR, // ^
TOK_DOUBLE_AND, // &&
TOK_DOUBLE_OR, // ||
TOK_QUERY, // ?
TOK_COLON, // :
TOKEN_TYPE__ASSIGNMENTS_BEGIN,
TOK_EQ = TOKEN_TYPE__ASSIGNMENTS_BEGIN, // =
TOK_PLUS_EQ, // +=
TOK_MINUS_EQ, // -=
TOK_MULT_EQ, // *=
TOK_MOD_EQ, // %=
TOK_LSHIFT_EQ, // <<=
TOK_RSHIFT_EQ, // >>=
TOK_RSHIFT_EX_EQ, // >>>=
TOK_AND_EQ, // &=
TOK_OR_EQ, // |=
TOK_XOR_EQ, // ^=
TOK_DIV_EQ, // /=
TOKEN_TYPE__ASSIGNMENTS_END = TOK_DIV_EQ,
TOK_EMPTY,
TOK_REGEXP, // RegularExpressionLiteral (/.../gim)
TOKEN_TYPE__KEYWORD_BEGIN,
TOK_KW_BREAK,
TOK_KW_CASE,
TOK_KW_CATCH,
TOK_KW_CLASS,
TOK_KW_CONST,
TOK_KW_CONTINUE,
TOK_KW_DEBUGGER,
TOK_KW_DEFAULT,
TOK_KW_DELETE,
TOK_KW_DO,
TOK_KW_ELSE,
TOK_KW_ENUM,
TOK_KW_EXPORT,
TOK_KW_EXTENDS,
TOK_KW_FINALLY,
TOK_KW_FOR,
TOK_KW_FUNCTION,
TOK_KW_IF,
TOK_KW_IN,
TOK_KW_INSTANCEOF,
TOK_KW_INTERFACE,
TOK_KW_IMPORT,
TOK_KW_IMPLEMENTS,
TOK_KW_LET,
TOK_KW_NEW,
TOK_KW_PACKAGE,
TOK_KW_PRIVATE,
TOK_KW_PROTECTED,
TOK_KW_PUBLIC,
TOK_KW_RETURN,
TOK_KW_STATIC,
TOK_KW_SUPER,
TOK_KW_SWITCH,
TOK_KW_THIS,
TOK_KW_THROW,
TOK_KW_TRY,
TOK_KW_TYPEOF,
TOK_KW_VAR,
TOK_KW_VOID,
TOK_KW_WHILE,
TOK_KW_WITH,
TOK_KW_YIELD,
TOKEN_TYPE__KEYWORD_END = TOK_KW_YIELD,
TOKEN_TYPE__END = TOKEN_TYPE__KEYWORD_END
} jsp_token_type_t;
/* Flags, describing token properties */
typedef enum
{
JSP_TOKEN_FLAG__NO_FLAGS = 0x00, /* default flag */
JSP_TOKEN_FLAG_PRECEDED_BY_NEWLINES = 0x01 /* designates that newline precedes the token */
} jsp_token_flag_t;
typedef lit_utf8_iterator_pos_t locus;
/* Represents the contents of a token. */
typedef struct
{
locus loc; /**< token location */
uint16_t uid; /**< encodes token's value, depending on token type */
uint8_t type; /**< token type */
uint8_t flags; /**< token flags */
} token;
/**
* Initializer for empty token
*/
#define TOKEN_EMPTY_INITIALIZER {LIT_ITERATOR_POS_ZERO, 0, TOK_EMPTY, JSP_TOKEN_FLAG__NO_FLAGS}
void lexer_init (const jerry_api_char_t *, size_t, bool);
token lexer_next_token (bool, bool);
void lexer_seek (locus);
void lexer_locus_to_line_and_column (locus, size_t *, size_t *);
void lexer_dump_line (size_t);
const char *lexer_token_type_to_string (jsp_token_type_t);
jsp_token_type_t lexer_get_token_type (token);
bool lexer_is_preceded_by_newlines (token);
extern bool lexer_are_tokens_with_same_identifier (token, token);
extern bool lexer_is_no_escape_sequences_in_token_string (token);
#endif
File diff suppressed because it is too large Load Diff
-199
View File
@@ -1,199 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef OPCODES_DUMPER_H
#define OPCODES_DUMPER_H
#include "ecma-globals.h"
#include "jsp-internal.h"
#include "lexer.h"
#include "lit-literal.h"
#include "opcodes.h"
#include "rcs-records.h"
#include "scopes-tree.h"
/**
* Operand types
*/
typedef enum __attr_packed___
{
JSP_OPERAND_TYPE_EMPTY, /**< empty operand */
JSP_OPERAND_TYPE_STRING_LITERAL, /**< operand contains string literal value */
JSP_OPERAND_TYPE_NUMBER_LITERAL, /**< operand contains number literal value */
JSP_OPERAND_TYPE_REGEXP_LITERAL, /**< operand contains regexp literal value */
JSP_OPERAND_TYPE_SIMPLE_VALUE, /**< operand contains a simple ecma value */
JSP_OPERAND_TYPE_SMALLINT, /**< operand contains small integer value (less than 256) */
JSP_OPERAND_TYPE_IDENTIFIER, /**< Identifier reference */
JSP_OPERAND_TYPE_THIS_BINDING, /**< ThisBinding operand */
JSP_OPERAND_TYPE_TMP, /**< operand contains byte-code register index */
JSP_OPERAND_TYPE_IDX_CONST, /**< operand contains an integer constant that fits vm_idx_t */
JSP_OPERAND_TYPE_UNKNOWN, /**< operand, representing unknown value that would be rewritten later */
JSP_OPERAND_TYPE_UNINITIALIZED /**< uninitialized operand
*
* Note:
* For use only in assertions to check that operands
* are initialized before actual usage */
} jsp_operand_type_t;
/**
* Operand (descriptor of value or reference in context of parser)
*/
typedef struct
{
union
{
vm_idx_t idx_const; /**< idx constant value (for jsp_operand_t::IDX_CONST) */
vm_idx_t uid; /**< register index (for jsp_operand_t::TMP) */
lit_cpointer_t lit_id; /**< literal (for jsp_operand_t::LITERAL) */
lit_cpointer_t identifier; /**< Identifier reference (is_value_based_ref flag not set) */
uint8_t smallint_value; /**< small integer value */
uint8_t simple_value; /**< simple ecma value */
} data;
jsp_operand_type_t type; /**< type of operand */
} jsp_operand_t;
extern jsp_operand_t jsp_make_uninitialized_operand (void);
extern jsp_operand_t jsp_make_empty_operand (void);
extern jsp_operand_t jsp_make_this_operand (void);
extern jsp_operand_t jsp_make_unknown_operand (void);
extern jsp_operand_t jsp_make_idx_const_operand (vm_idx_t);
extern jsp_operand_t jsp_make_smallint_operand (uint8_t);
extern jsp_operand_t jsp_make_simple_value_operand (ecma_simple_value_t);
extern jsp_operand_t jsp_make_string_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_regexp_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_number_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_identifier_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_reg_operand (vm_idx_t);
extern bool jsp_is_empty_operand (jsp_operand_t);
extern bool jsp_is_this_operand (jsp_operand_t);
extern bool jsp_is_unknown_operand (jsp_operand_t);
extern bool jsp_is_idx_const_operand (jsp_operand_t);
extern bool jsp_is_register_operand (jsp_operand_t);
extern bool jsp_is_simple_value_operand (jsp_operand_t);
extern bool jsp_is_smallint_operand (jsp_operand_t);
extern bool jsp_is_number_lit_operand (jsp_operand_t);
extern bool jsp_is_string_lit_operand (jsp_operand_t);
extern bool jsp_is_regexp_lit_operand (jsp_operand_t);
extern bool jsp_is_identifier_operand (jsp_operand_t);
extern lit_cpointer_t jsp_operand_get_identifier_name (jsp_operand_t);
extern lit_cpointer_t jsp_operand_get_literal (jsp_operand_t);
extern vm_idx_t jsp_operand_get_idx (jsp_operand_t);
extern vm_idx_t jsp_operand_get_idx_const (jsp_operand_t);
extern ecma_simple_value_t jsp_operand_get_simple_value (jsp_operand_t);
extern uint8_t jsp_operand_get_smallint_value (jsp_operand_t);
JERRY_STATIC_ASSERT (sizeof (jsp_operand_t) == 4);
typedef enum __attr_packed___
{
VARG_FUNC_DECL,
VARG_FUNC_EXPR,
VARG_ARRAY_DECL,
VARG_OBJ_DECL,
VARG_CONSTRUCT_EXPR,
VARG_CALL_EXPR
} varg_list_type;
extern jsp_operand_t empty_operand (void);
extern jsp_operand_t tmp_operand (void);
extern bool operand_is_empty (jsp_operand_t);
extern void dumper_init (jsp_ctx_t *, bool);
extern vm_instr_counter_t dumper_get_current_instr_counter (jsp_ctx_t *);
extern void dumper_start_move_of_vars_to_regs (jsp_ctx_t *);
extern bool dumper_start_move_of_args_to_regs (jsp_ctx_t *, uint32_t args_num);
extern bool dumper_try_replace_identifier_name_with_reg (jsp_ctx_t *, bytecode_data_header_t *, op_meta *);
extern void dumper_alloc_reg_for_unused_arg (jsp_ctx_t *);
extern void dumper_new_statement (jsp_ctx_t *);
extern void dumper_save_reg_alloc_ctx (jsp_ctx_t *, vm_idx_t *, vm_idx_t *);
extern void dumper_restore_reg_alloc_ctx (jsp_ctx_t *, vm_idx_t, vm_idx_t, bool);
extern vm_idx_t dumper_save_reg_alloc_counter (jsp_ctx_t *);
extern void dumper_restore_reg_alloc_counter (jsp_ctx_t *, vm_idx_t);
extern bool dumper_is_eval_literal (jsp_operand_t);
extern void dump_variable_assignment (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_varg_header_for_rewrite (jsp_ctx_t *, varg_list_type, jsp_operand_t, jsp_operand_t);
extern void rewrite_varg_header_set_args_count (jsp_ctx_t *, size_t, vm_instr_counter_t);
extern void dump_call_additional_info (jsp_ctx_t *, opcode_call_flags_t, jsp_operand_t);
extern void dump_varg (jsp_ctx_t *, jsp_operand_t);
extern void dump_prop_name_and_value (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_getter_decl (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_setter_decl (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_getter (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern void dump_prop_setter (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_conditional_check_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_conditional_check (jsp_ctx_t *, vm_instr_counter_t);
extern vm_instr_counter_t dump_jump_to_end_for_rewrite (jsp_ctx_t *);
extern void rewrite_jump_to_end (jsp_ctx_t *, vm_instr_counter_t);
extern vm_instr_counter_t dumper_set_next_iteration_target (jsp_ctx_t *);
extern vm_instr_counter_t dump_simple_or_nested_jump_for_rewrite (jsp_ctx_t *,
bool,
bool,
bool,
jsp_operand_t,
vm_instr_counter_t);
extern vm_instr_counter_t rewrite_simple_or_nested_jump_and_get_next (jsp_ctx_t *,
vm_instr_counter_t,
vm_instr_counter_t);
extern void dump_continue_iterations_check (jsp_ctx_t *, vm_instr_counter_t, jsp_operand_t);
extern void dump_delete (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_delete_prop (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern void dump_typeof (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_unary_op (jsp_ctx_t *, vm_op_t, jsp_operand_t, jsp_operand_t);
extern void dump_binary_op (jsp_ctx_t *, vm_op_t, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_with_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_with (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_with_end (jsp_ctx_t *);
extern vm_instr_counter_t dump_for_in_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_for_in (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_for_in_end (jsp_ctx_t *);
extern vm_instr_counter_t dump_try_for_rewrite (jsp_ctx_t *);
extern vm_instr_counter_t dump_catch_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern vm_instr_counter_t dump_finally_for_rewrite (jsp_ctx_t *);
extern void rewrite_try (jsp_ctx_t *, vm_instr_counter_t);
extern void rewrite_catch (jsp_ctx_t *, vm_instr_counter_t);
extern void rewrite_finally (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_end_try_catch_finally (jsp_ctx_t *);
extern void dump_throw (jsp_ctx_t *, jsp_operand_t);
extern void dump_variable_declaration (jsp_ctx_t *, lit_cpointer_t);
extern vm_instr_counter_t dump_reg_var_decl_for_rewrite (jsp_ctx_t *);
extern void rewrite_reg_var_decl (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_ret (jsp_ctx_t *);
extern void dump_retval (jsp_ctx_t *, jsp_operand_t);
extern op_meta dumper_get_op_meta (jsp_ctx_t *, vm_instr_counter_t);
extern void dumper_rewrite_op_meta (jsp_ctx_t *, vm_instr_counter_t, op_meta);
#endif /* !OPCODES_DUMPER_H */
File diff suppressed because it is too large Load Diff
+28 -8
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,40 @@
#ifndef PARSER_H
#define PARSER_H
#include "jrt.h"
#include "jerry-api.h"
#include "byte-code.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser ECMAScript
* @{
*
* \addtogroup jsparser_parser Parser
* @{
*/
/**
* Parser completion status
*/
typedef enum
{
JSP_STATUS_OK, /**< parse finished successfully, no early errors occured */
JSP_STATUS_SYNTAX_ERROR, /**< SyntaxError early error occured */
JSP_STATUS_OK, /**< parse finished successfully, no early errors occured */
JSP_STATUS_SYNTAX_ERROR, /**< SyntaxError early error occured */
JSP_STATUS_REFERENCE_ERROR /**< ReferenceError early error occured */
} jsp_status_t;
void parser_set_show_instrs (bool);
jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t, const bytecode_data_header_t **);
jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool, const bytecode_data_header_t **, bool *);
extern void parser_set_show_instrs (int);
#endif /* PARSER_H */
extern jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t,
ecma_compiled_code_t **);
extern jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool,
ecma_compiled_code_t **);
/**
* @}
* @}
* @}
*/
#endif /* !PARSER_H */
-296
View File
@@ -1,296 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "jsp-mm.h"
#include "scopes-tree.h"
scopes_tree scopes_tree_root_node_p = NULL;
scopes_tree scopes_tree_last_node_p = NULL;
static void
assert_tree (scopes_tree t)
{
JERRY_ASSERT (t != NULL);
}
vm_instr_counter_t
scopes_tree_instrs_num (scopes_tree t)
{
assert_tree (t);
return t->instrs_count;
}
/**
* Get number of variable declarations in the scope
*
* @return number of variable declarations
*/
vm_instr_counter_t
scopes_tree_var_decls_num (scopes_tree t) /**< scope */
{
assert_tree (t);
return linked_list_get_length (t->var_decls);
} /* scopes_tree_var_decls_num */
/**
* Add variable declaration to a scope
*/
void
scopes_tree_add_var_decl (scopes_tree tree, /**< scope, to which variable declaration is added */
op_meta op) /**< variable declaration instruction */
{
assert_tree (tree);
linked_list_set_element (tree->var_decls, linked_list_get_length (tree->var_decls), &op);
} /* scopes_tree_add_var_decl */
/**
* Get variable declaration for the specified scope
*
* @return instruction, declaring a variable
*/
op_meta
scopes_tree_var_decl (scopes_tree tree, /**< scope, from which variable declaration is retrieved */
vm_instr_counter_t oc) /**< number of variable declaration in the scope */
{
assert_tree (tree);
JERRY_ASSERT (oc < linked_list_get_length (tree->var_decls));
return *(op_meta *) linked_list_element (tree->var_decls, oc);
} /* scopes_tree_var_decl */
/**
* Checks if variable declaration exists in the scope
*
* @return true / false
*/
bool
scopes_tree_variable_declaration_exists (scopes_tree tree, /**< scope */
lit_cpointer_t lit_id) /**< literal which holds variable's name */
{
assert_tree (tree);
for (vm_instr_counter_t oc = 0u;
oc < linked_list_get_length (tree->var_decls);
oc++)
{
const op_meta* var_decl_om_p = (op_meta *) linked_list_element (tree->var_decls, oc);
JERRY_ASSERT (var_decl_om_p->op.op_idx == VM_OP_VAR_DECL);
JERRY_ASSERT (var_decl_om_p->op.data.var_decl.variable_name == VM_IDX_REWRITE_LITERAL_UID);
if (var_decl_om_p->lit_id[0].packed_value == lit_id.packed_value)
{
return true;
}
}
return false;
} /* scopes_tree_variable_declaration_exists */
/**
* Fill variable declaration list of bytecode header
*/
void
scopes_tree_dump_var_decls (scopes_tree scope, /**< scopes tree */
lit_cpointer_t *var_decls_p) /**< pointer to bytecode header's declarations table,
* where variables' lit_cp's should be stored */
{
for (uint32_t i = 0; i < scopes_tree_var_decls_num (scope); ++i)
{
op_meta var_decl_op_meta = *(op_meta *) linked_list_element (scope->var_decls, i);
var_decls_p[i] = var_decl_op_meta.lit_id[0];
}
} /* scopes_tree_dump_var_decls */
/**
* Set up a flag, indicating that scope should be executed in strict mode
*/
void
scopes_tree_set_strict_mode (scopes_tree tree, /**< scope */
bool strict_mode) /**< value of the strict mode flag */
{
assert_tree (tree);
tree->strict_mode = strict_mode;
} /* scopes_tree_set_strict_mode */
/**
* Set up a flag, indicating that "arguments" is used inside a scope
*/
void
scopes_tree_set_arguments_used (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->ref_arguments = true;
} /* merge_subscopes */
/**
* Set up a flag, indicating that "eval" is used inside a scope
*/
void
scopes_tree_set_eval_used (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->ref_eval = true;
} /* scopes_tree_set_eval_used */
/**
* Set up a flag, indicating that 'with' statement is contained in a scope
*/
void
scopes_tree_set_contains_with (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_with = true;
} /* scopes_tree_set_contains_with */
/**
* Set up a flag, indicating that 'try' statement is contained in a scope
*/
void
scopes_tree_set_contains_try (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_try = true;
} /* scopes_tree_set_contains_try */
/**
* Set up a flag, indicating that 'delete' operator is contained in a scope
*/
void
scopes_tree_set_contains_delete (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_delete = true;
} /* scopes_tree_set_contains_delete */
/**
* Set up a flag, indicating that there is a function declaration / expression inside a scope
*/
void
scopes_tree_set_contains_functions (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_functions = true;
} /* scopes_tree_set_contains_functions */
bool
scopes_tree_strict_mode (scopes_tree tree)
{
assert_tree (tree);
return (bool) tree->strict_mode;
}
/**
* Get number of subscopes (immediate function declarations / expressions) of the specified scope
*
* @return the number
*/
size_t
scopes_tree_child_scopes_num (scopes_tree tree) /**< a scopes tree node */
{
return tree->child_scopes_num;
} /* scopes_tree_child_scopes_num */
void
scopes_tree_init (void)
{
scopes_tree_root_node_p = NULL;
scopes_tree_last_node_p = NULL;
} /* scopes_tree_init */
void
scopes_tree_finalize (void)
{
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
} /* scopes_tree_finalize */
/**
* Initialize a scope
*
* @return initialized scope
*/
scopes_tree
scopes_tree_new_scope (scopes_tree parent, /**< parent scope */
scope_type_t type) /**< scope type */
{
scopes_tree tree = (scopes_tree) jsp_mm_alloc (sizeof (scopes_tree_int));
tree->child_scopes_num = 0;
tree->child_scopes_processed_num = 0;
tree->max_uniq_literals_num = 0;
tree->bc_header_cp = MEM_CP_NULL;
tree->next_scope_cp = MEM_CP_NULL;
tree->instrs_count = 0;
tree->type = type;
tree->strict_mode = false;
tree->ref_arguments = false;
tree->ref_eval = false;
tree->contains_with = false;
tree->contains_try = false;
tree->contains_delete = false;
tree->contains_functions = false;
tree->is_vars_and_args_to_regs_possible = false;
tree->var_decls = linked_list_init (sizeof (op_meta));
if (parent != NULL)
{
JERRY_ASSERT (scopes_tree_root_node_p != NULL);
JERRY_ASSERT (scopes_tree_last_node_p != NULL);
parent->child_scopes_num++;
}
else
{
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
scopes_tree_root_node_p = tree;
scopes_tree_last_node_p = tree;
}
MEM_CP_SET_NON_NULL_POINTER (scopes_tree_last_node_p->next_scope_cp, tree);
tree->next_scope_cp = MEM_CP_NULL;
scopes_tree_last_node_p = tree;
return tree;
} /* scopes_tree_new_scope */
void
scopes_tree_finish_build (void)
{
JERRY_ASSERT (scopes_tree_root_node_p != NULL);
JERRY_ASSERT (scopes_tree_last_node_p != NULL);
scopes_tree_root_node_p = NULL;
scopes_tree_last_node_p = NULL;
} /* scopes_tree_finish_build */
void
scopes_tree_free_scope (scopes_tree scope_p)
{
assert_tree (scope_p);
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
linked_list_free (scope_p->var_decls);
jsp_mm_free (scope_p);
} /* scopes_tree_free_scope */
-112
View File
@@ -1,112 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef SCOPES_TREE_H
#define SCOPES_TREE_H
#include "linked-list.h"
#include "lexer.h"
#include "ecma-globals.h"
#include "opcodes.h"
#include "lit-id-hash-table.h"
#include "lit-literal.h"
/**
* Intermediate instruction descriptor that additionally to byte-code instruction
* holds information about literals, associated with corresponding arguments
* of the instruction.
*/
typedef struct
{
lit_cpointer_t lit_id[3]; /**< literals, corresponding to arguments
* (NOT_A_LITERAL - if not literal is associated
* with corresponding argument) */
vm_instr_t op; /**< byte-code instruction */
} op_meta;
typedef struct tree_header
{
linked_list children;
} tree_header;
/**
* Scope type
*/
typedef enum __attr_packed___
{
SCOPE_TYPE_GLOBAL, /**< the Global code scope */
SCOPE_TYPE_FUNCTION, /**< a function code scope */
SCOPE_TYPE_EVAL /**< an eval code scope */
} scope_type_t;
/**
* Structure for holding scope information during parsing
*/
typedef struct
{
mem_cpointer_t next_scope_cp; /**< next scope with same parent */
mem_cpointer_t bc_header_cp; /**< pointer to corresponding byte-code header
* (after bc_dump_single_scope) */
uint16_t child_scopes_num; /**< number of child scopes */
uint16_t child_scopes_processed_num; /**< number of child scopes, for which
* byte-code headers were already constructed */
uint16_t max_uniq_literals_num; /**< upper estimate number of entries
* in idx-literal hash table */
vm_instr_counter_t instrs_count; /**< count of instructions */
linked_list var_decls; /**< instructions for variable declarations */
scope_type_t type : 2; /**< scope type */
bool strict_mode: 1; /**< flag, indicating that scope's code should be executed in strict mode */
bool ref_arguments: 1; /**< flag, indicating that "arguments" variable is used inside the scope
* (not depends on subscopes) */
bool ref_eval: 1; /**< flag, indicating that "eval" is used inside the scope
* (not depends on subscopes) */
bool contains_with: 1; /**< flag, indicationg whether 'with' statement is contained in the scope
* (not depends on subscopes) */
bool contains_try: 1; /**< flag, indicationg whether 'try' statement is contained in the scope
* (not depends on subscopes) */
bool contains_delete: 1; /**< flag, indicationg whether 'delete' operator is contained in the scope
* (not depends on subscopes) */
bool contains_functions: 1; /**< flag, indicating that the scope contains a function declaration / expression */
bool is_vars_and_args_to_regs_possible : 1; /**< the function's variables / arguments can be moved to registers */
} scopes_tree_int;
typedef scopes_tree_int *scopes_tree;
void scopes_tree_init (void);
void scopes_tree_finalize (void);
scopes_tree scopes_tree_new_scope (scopes_tree, scope_type_t);
void scopes_tree_free_scope (scopes_tree);
void scopes_tree_finish_build (void);
size_t scopes_tree_child_scopes_num (scopes_tree);
vm_instr_counter_t scopes_tree_instrs_num (scopes_tree);
vm_instr_counter_t scopes_tree_var_decls_num (scopes_tree);
void scopes_tree_add_var_decl (scopes_tree, op_meta);
op_meta scopes_tree_var_decl (scopes_tree, vm_instr_counter_t);
bool scopes_tree_variable_declaration_exists (scopes_tree, lit_cpointer_t);
void scopes_tree_dump_var_decls (scopes_tree, lit_cpointer_t *);
void scopes_tree_set_strict_mode (scopes_tree, bool);
void scopes_tree_set_arguments_used (scopes_tree);
void scopes_tree_set_eval_used (scopes_tree);
void scopes_tree_set_contains_with (scopes_tree);
void scopes_tree_set_contains_try (scopes_tree);
void scopes_tree_set_contains_delete (scopes_tree);
void scopes_tree_set_contains_functions (scopes_tree);
bool scopes_tree_strict_mode (scopes_tree);
#endif /* SCOPES_TREE_H */
+67 -34
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,16 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_bytecode Bytecode
* @{
*/
/**
* Size of block of RegExp bytecode. Used for allocation
*/
@@ -34,7 +44,7 @@
* Get length of bytecode
*/
static uint32_t
re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p)
re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
return ((uint32_t) (bc_ctx_p->current_p - bc_ctx_p->block_start_p));
} /* re_get_bytecode_length */
@@ -47,7 +57,7 @@ re_dump_bytecode (re_bytecode_ctx_t *bc_ctx);
*
* @return current position in RegExp bytecode
*/
static re_bytecode_t*
static uint8_t *
re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
JERRY_ASSERT (bc_ctx_p->block_end_p - bc_ctx_p->block_start_p >= 0);
@@ -62,8 +72,8 @@ re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytec
JERRY_ASSERT (bc_ctx_p->current_p - bc_ctx_p->block_start_p >= 0);
size_t current_ptr_offset = static_cast<size_t> (bc_ctx_p->current_p - bc_ctx_p->block_start_p);
re_bytecode_t *new_block_start_p = (re_bytecode_t *) mem_heap_alloc_block (new_block_size,
MEM_HEAP_ALLOC_SHORT_TERM);
uint8_t *new_block_start_p = (uint8_t *) mem_heap_alloc_block (new_block_size,
MEM_HEAP_ALLOC_SHORT_TERM);
if (bc_ctx_p->current_p)
{
memcpy (new_block_start_p, bc_ctx_p->block_start_p, static_cast<size_t> (current_ptr_offset));
@@ -81,12 +91,12 @@ re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytec
*/
static void
re_bytecode_list_append (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
re_bytecode_t *bytecode_p, /**< input bytecode */
uint8_t *bytecode_p, /**< input bytecode */
size_t length) /**< length of input */
{
JERRY_ASSERT (length <= REGEXP_BYTECODE_BLOCK_SIZE);
re_bytecode_t *current_p = bc_ctx_p->current_p;
uint8_t *current_p = bc_ctx_p->current_p;
if (current_p + length > bc_ctx_p->block_end_p)
{
current_p = re_realloc_regexp_bytecode_block (bc_ctx_p);
@@ -102,24 +112,24 @@ re_bytecode_list_append (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode conte
static void
re_bytecode_list_insert (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
size_t offset, /**< distance from the start of the container */
re_bytecode_t *bytecode_p, /**< input bytecode */
uint8_t *bytecode_p, /**< input bytecode */
size_t length) /**< length of input */
{
JERRY_ASSERT (length <= REGEXP_BYTECODE_BLOCK_SIZE);
re_bytecode_t *current_p = bc_ctx_p->current_p;
uint8_t *current_p = bc_ctx_p->current_p;
if (current_p + length > bc_ctx_p->block_end_p)
{
re_realloc_regexp_bytecode_block (bc_ctx_p);
}
re_bytecode_t *src_p = bc_ctx_p->block_start_p + offset;
uint8_t *src_p = bc_ctx_p->block_start_p + offset;
if ((re_get_bytecode_length (bc_ctx_p) - offset) > 0)
{
re_bytecode_t *dest_p = src_p + length;
re_bytecode_t *tmp_block_start_p;
tmp_block_start_p = (re_bytecode_t *) mem_heap_alloc_block ((re_get_bytecode_length (bc_ctx_p) - offset),
MEM_HEAP_ALLOC_SHORT_TERM);
uint8_t *dest_p = src_p + length;
uint8_t *tmp_block_start_p;
tmp_block_start_p = (uint8_t *) mem_heap_alloc_block ((re_get_bytecode_length (bc_ctx_p) - offset),
MEM_HEAP_ALLOC_SHORT_TERM);
memcpy (tmp_block_start_p, src_p, (size_t) (re_get_bytecode_length (bc_ctx_p) - offset));
memcpy (dest_p, tmp_block_start_p, (size_t) (re_get_bytecode_length (bc_ctx_p) - offset));
mem_heap_free_block (tmp_block_start_p);
@@ -136,7 +146,7 @@ static void
re_append_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
re_opcode_t opcode) /**< input opcode */
{
re_bytecode_list_append (bc_ctx_p, (re_bytecode_t*) &opcode, sizeof (re_bytecode_t));
re_bytecode_list_append (bc_ctx_p, (uint8_t*) &opcode, sizeof (uint8_t));
} /* re_append_opcode */
/**
@@ -146,7 +156,7 @@ static void
re_append_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t value) /**< input value */
{
re_bytecode_list_append (bc_ctx_p, (re_bytecode_t*) &value, sizeof (uint32_t));
re_bytecode_list_append (bc_ctx_p, (uint8_t*) &value, sizeof (uint32_t));
} /* re_append_u32 */
/**
@@ -168,7 +178,7 @@ re_insert_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t offset, /**< distance from the start of the container */
re_opcode_t opcode) /**< input opcode */
{
re_bytecode_list_insert (bc_ctx_p, offset, (re_bytecode_t*) &opcode, sizeof (re_bytecode_t));
re_bytecode_list_insert (bc_ctx_p, offset, (uint8_t*) &opcode, sizeof (uint8_t));
} /* re_insert_opcode */
/**
@@ -179,17 +189,17 @@ re_insert_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t offset, /**< distance from the start of the container */
uint32_t value) /**< input value */
{
re_bytecode_list_insert (bc_ctx_p, offset, (re_bytecode_t*) &value, sizeof (uint32_t));
re_bytecode_list_insert (bc_ctx_p, offset, (uint8_t*) &value, sizeof (uint32_t));
} /* re_insert_u32 */
/**
* Get a RegExp opcode
*/
re_opcode_t
re_get_opcode (re_bytecode_t **bc_p) /**< pointer to bytecode start */
re_get_opcode (uint8_t **bc_p) /**< pointer to bytecode start */
{
re_bytecode_t bytecode = **bc_p;
(*bc_p) += sizeof (re_bytecode_t);
uint8_t bytecode = **bc_p;
(*bc_p) += sizeof (uint8_t);
return (re_opcode_t) bytecode;
} /* get_opcode */
@@ -197,7 +207,7 @@ re_get_opcode (re_bytecode_t **bc_p) /**< pointer to bytecode start */
* Get a parameter of a RegExp opcode
*/
uint32_t
re_get_value (re_bytecode_t **bc_p) /**< pointer to bytecode start */
re_get_value (uint8_t **bc_p) /**< pointer to bytecode start */
{
uint32_t value = *((uint32_t*) *bc_p);
(*bc_p) += sizeof (uint32_t);
@@ -368,6 +378,13 @@ re_insert_into_group_with_jump (re_compiler_ctx_t *re_ctx_p, /**< RegExp compile
re_insert_into_group (re_ctx_p, group_start_offset, idx, is_capturable);
} /* re_insert_into_group_with_jump */
/**
* @}
*
* \addtogroup regexparser_compiler Compiler
* @{
*/
/**
* Parse alternatives
*
@@ -614,9 +631,9 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecode */
re_compile_bytecode (re_compiled_code_t **out_bytecode_p, /**< out:pointer to bytecode */
ecma_string_t *pattern_str_p, /**< pattern */
uint8_t flags) /**< flags */
uint16_t flags) /**< flags */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
re_compiler_ctx_t re_ctx;
@@ -661,9 +678,18 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
re_append_opcode (&bc_ctx, RE_OP_EOF);
/* 3. Insert extra informations for bytecode header */
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_non_captures);
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_captures * 2);
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.flags);
re_compiled_code_t re_compiled_code;
re_compiled_code.flags = re_ctx.flags | (1 << ECMA_BYTECODE_REF_SHIFT);
ECMA_SET_NON_NULL_POINTER (re_compiled_code.pattern_cp,
ecma_copy_or_ref_ecma_string (pattern_str_p));
re_compiled_code.num_of_captures = re_ctx.num_of_captures * 2;
re_compiled_code.num_of_non_captures = re_ctx.num_of_non_captures;
re_bytecode_list_insert (&bc_ctx,
0,
(uint8_t *) &re_compiled_code,
sizeof (re_compiled_code_t));
}
ECMA_FINALIZE (empty);
@@ -679,7 +705,7 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
{
/* The RegExp bytecode contains at least a RE_OP_SAVE_AT_START opdoce, so it cannot be NULL. */
JERRY_ASSERT (bc_ctx.block_start_p != NULL);
*out_bytecode_p = bc_ctx.block_start_p;
*out_bytecode_p = (re_compiled_code_t *) bc_ctx.block_start_p;
}
#ifdef JERRY_ENABLE_LOG
@@ -694,12 +720,14 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
* RegExp bytecode dumper
*/
void
re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p)
re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
re_bytecode_t *bytecode_p = bc_ctx_p->block_start_p;
JERRY_DLOG ("%d ", re_get_value (&bytecode_p));
JERRY_DLOG ("%d ", re_get_value (&bytecode_p));
JERRY_DLOG ("%d | ", re_get_value (&bytecode_p));
re_compiled_code_t *compiled_code_p = bc_ctx_p->block_start_p;
JERRY_DLOG ("%d ", compiled_code_p->flags);
JERRY_DLOG ("%d ", compiled_code_p->num_of_captures);
JERRY_DLOG ("%d | ", compiled_code_p->num_of_non_captures);
uint8_t *bytecode_p = (uint8_t *) (compiled_code_p + 1);
re_opcode_t op;
while ((op = re_get_opcode (&bytecode_p)))
@@ -891,4 +919,9 @@ re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p)
} /* re_dump_bytecode */
#endif /* JERRY_ENABLE_LOG */
/**
* @}
* @}
*/
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
+70 -48
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,16 @@
#include "ecma-globals.h"
#include "re-parser.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_compiler Compiler
* @{
*/
/**
* RegExp opcodes
*/
@@ -31,54 +41,60 @@ typedef enum
/* Group opcode order is important, because RE_IS_CAPTURE_GROUP is based on it.
* Change it carefully. Capture opcodes should be at first.
*/
RE_OP_CAPTURE_GROUP_START,
RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START,
RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START,
RE_OP_CAPTURE_GREEDY_GROUP_END,
RE_OP_CAPTURE_NON_GREEDY_GROUP_END,
RE_OP_NON_CAPTURE_GROUP_START,
RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START,
RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START,
RE_OP_NON_CAPTURE_GREEDY_GROUP_END,
RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END,
RE_OP_CAPTURE_GROUP_START, /**< group start */
RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START, /**< greedy zero group start */
RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-greedy zero group start */
RE_OP_CAPTURE_GREEDY_GROUP_END, /**< greedy group end */
RE_OP_CAPTURE_NON_GREEDY_GROUP_END, /**< non-greedy group end */
RE_OP_NON_CAPTURE_GROUP_START, /**< non-capture group start */
RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START, /**< non-capture greedy zero group start */
RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-capture non-greedy zero group start */
RE_OP_NON_CAPTURE_GREEDY_GROUP_END, /**< non-capture greedy group end */
RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END, /**< non-capture non-greedy group end */
RE_OP_MATCH,
RE_OP_CHAR,
RE_OP_SAVE_AT_START,
RE_OP_SAVE_AND_MATCH,
RE_OP_PERIOD,
RE_OP_ALTERNATIVE,
RE_OP_GREEDY_ITERATOR,
RE_OP_NON_GREEDY_ITERATOR,
RE_OP_ASSERT_START,
RE_OP_ASSERT_END,
RE_OP_ASSERT_WORD_BOUNDARY,
RE_OP_ASSERT_NOT_WORD_BOUNDARY,
RE_OP_LOOKAHEAD_POS,
RE_OP_LOOKAHEAD_NEG,
RE_OP_BACKREFERENCE,
RE_OP_CHAR_CLASS,
RE_OP_INV_CHAR_CLASS
RE_OP_MATCH, /**< match */
RE_OP_CHAR, /**< any character */
RE_OP_SAVE_AT_START, /**< save at start */
RE_OP_SAVE_AND_MATCH, /**< save and match */
RE_OP_PERIOD, /**< . */
RE_OP_ALTERNATIVE, /**< | */
RE_OP_GREEDY_ITERATOR, /**< greedy iterator */
RE_OP_NON_GREEDY_ITERATOR, /**< non-greedy iterator */
RE_OP_ASSERT_START, /**< ^ */
RE_OP_ASSERT_END, /**< $ */
RE_OP_ASSERT_WORD_BOUNDARY, /**< \b */
RE_OP_ASSERT_NOT_WORD_BOUNDARY, /**< \B */
RE_OP_LOOKAHEAD_POS, /**< lookahead pos */
RE_OP_LOOKAHEAD_NEG, /**< lookahead neg */
RE_OP_BACKREFERENCE, /**< \[0..9] */
RE_OP_CHAR_CLASS, /**< [ ] */
RE_OP_INV_CHAR_CLASS /**< [^ ] */
} re_opcode_t;
/**
* Compiled byte code data.
*/
typedef struct
{
uint16_t flags; /**< RegExp flags */
mem_cpointer_t pattern_cp; /**< original RegExp pattern */
uint32_t num_of_captures; /**< number of capturing brackets */
uint32_t num_of_non_captures; /**< number of non capturing brackets */
} re_compiled_code_t;
/**
* Check if a RegExp opcode is a capture group or not
*/
#define RE_IS_CAPTURE_GROUP(x) (((x) < RE_OP_NON_CAPTURE_GROUP_START) ? 1 : 0)
/**
* Type of bytecode elements
*/
typedef uint8_t re_bytecode_t;
/**
* Context of RegExp bytecode container
*/
typedef struct
{
re_bytecode_t *block_start_p; /**< start of bytecode block */
re_bytecode_t *block_end_p; /**< end of bytecode block */
re_bytecode_t *current_p; /**< current position in bytecode */
uint8_t *block_start_p; /**< start of bytecode block */
uint8_t *block_end_p; /**< end of bytecode block */
uint8_t *current_p; /**< current position in bytecode */
} re_bytecode_ctx_t;
/**
@@ -86,23 +102,29 @@ typedef struct
*/
typedef struct
{
uint8_t flags; /**< RegExp flags */
uint32_t num_of_captures; /**< number of capture groups */
uint32_t num_of_non_captures; /**< number of non-capture groups */
uint32_t highest_backref; /**< highest backreference */
uint16_t flags; /**< RegExp flags */
uint32_t num_of_captures; /**< number of capture groups */
uint32_t num_of_non_captures; /**< number of non-capture groups */
uint32_t highest_backref; /**< highest backreference */
re_bytecode_ctx_t *bytecode_ctx_p; /**< pointer of RegExp bytecode context */
re_token_t current_token; /**< current token */
re_parser_ctx_t *parser_ctx_p; /**< pointer of RegExp parser context */
re_token_t current_token; /**< current token */
re_parser_ctx_t *parser_ctx_p; /**< pointer of RegExp parser context */
} re_compiler_ctx_t;
ecma_completion_value_t
re_compile_bytecode (re_bytecode_t **, ecma_string_t *, uint8_t);
re_compile_bytecode (re_compiled_code_t **, ecma_string_t *, uint16_t);
re_opcode_t
re_get_opcode (re_bytecode_t **);
re_get_opcode (uint8_t **);
uint32_t
re_get_value (re_bytecode_t **);
re_get_value (uint8_t **);
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* RE_COMPILER_H */
/**
* @}
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* !RE_COMPILER_H */
+17 -1
View File
@@ -24,6 +24,16 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_parser Parser
* @{
*/
/**
* Lookup a character in the input string.
*
@@ -894,4 +904,10 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context *
return ret_value;
} /* re_parse_next_token */
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
/**
* @}
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
+61 -40
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,49 +19,65 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
#include "opcodes-dumper.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_bytecode Bytecode
* @{
*/
/**
* RegExp token type definitions
*/
typedef enum
{
RE_TOK_EOF, /* EOF */
RE_TOK_BACKREFERENCE, /* \[0..9] */
RE_TOK_CHAR, /* any character */
RE_TOK_ALTERNATIVE, /* | */
RE_TOK_ASSERT_START, /* ^ */
RE_TOK_ASSERT_END, /* $ */
RE_TOK_PERIOD, /* . */
RE_TOK_START_CAPTURE_GROUP, /* ( */
RE_TOK_START_NON_CAPTURE_GROUP, /* (?: */
RE_TOK_END_GROUP, /* ')' */
RE_TOK_EOF, /* EOF */
RE_TOK_BACKREFERENCE, /* \[0..9] */
RE_TOK_CHAR, /* any character */
RE_TOK_ALTERNATIVE, /* | */
RE_TOK_ASSERT_START, /* ^ */
RE_TOK_ASSERT_END, /* $ */
RE_TOK_PERIOD, /* . */
RE_TOK_START_CAPTURE_GROUP, /* ( */
RE_TOK_START_NON_CAPTURE_GROUP, /* (?: */
RE_TOK_END_GROUP, /* ')' */
RE_TOK_ASSERT_START_POS_LOOKAHEAD, /* (?= */
RE_TOK_ASSERT_START_NEG_LOOKAHEAD, /* (?! */
RE_TOK_ASSERT_WORD_BOUNDARY, /* \b */
RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /* \B */
RE_TOK_DIGIT, /* \d */
RE_TOK_NOT_DIGIT, /* \D */
RE_TOK_WHITE, /* \s */
RE_TOK_NOT_WHITE, /* \S */
RE_TOK_WORD_CHAR, /* \w */
RE_TOK_NOT_WORD_CHAR, /* \W */
RE_TOK_START_CHAR_CLASS, /* [ ] */
RE_TOK_START_INV_CHAR_CLASS, /* [^ ] */
RE_TOK_ASSERT_WORD_BOUNDARY, /* \b */
RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /* \B */
RE_TOK_DIGIT, /* \d */
RE_TOK_NOT_DIGIT, /* \D */
RE_TOK_WHITE, /* \s */
RE_TOK_NOT_WHITE, /* \S */
RE_TOK_WORD_CHAR, /* \w */
RE_TOK_NOT_WORD_CHAR, /* \W */
RE_TOK_START_CHAR_CLASS, /* [ ] */
RE_TOK_START_INV_CHAR_CLASS, /* [^ ] */
} re_token_type_t;
/**
* RegExp constant of infinite
*/
* @}
*
* \addtogroup regexparser_parser Parser
* @{
*/
/**
* RegExp constant of infinite
*/
#define RE_ITERATOR_INFINITE ((uint32_t)-1)
/**
* Maximum number of decimal escape digits
*/
* Maximum number of decimal escape digits
*/
#define RE_MAX_RE_DECESC_DIGITS 9
/**
* Undefined character (out of the range of the codeunit)
*/
* Undefined character (out of the range of the codeunit)
*/
#define RE_CHAR_UNDEF 0xFFFFFFFF
/**
@@ -69,11 +85,11 @@ typedef enum
*/
typedef struct
{
re_token_type_t type; /**< type of the token */
uint32_t value; /**< value of the token */
uint32_t qmin; /**< minimum number of token iterations */
uint32_t qmax; /**< maximum number of token iterations */
bool greedy; /**< type of iteration */
re_token_type_t type; /**< type of the token */
uint32_t value; /**< value of the token */
uint32_t qmin; /**< minimum number of token iterations */
uint32_t qmax; /**< maximum number of token iterations */
bool greedy; /**< type of iteration */
} re_token_t;
/**
@@ -82,10 +98,10 @@ typedef struct
typedef struct
{
lit_utf8_byte_t *input_start_p; /**< start of input pattern */
lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */
lit_utf8_byte_t *input_end_p; /**< end of input pattern */
int num_of_groups; /**< number of groups */
uint32_t num_of_classes; /**< number of character classes */
lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */
lit_utf8_byte_t *input_end_p; /**< end of input pattern */
int num_of_groups; /**< number of groups */
uint32_t num_of_classes; /**< number of character classes */
} re_parser_ctx_t;
typedef void (*re_char_class_callback) (void *re_ctx_p, uint32_t start, uint32_t end);
@@ -96,5 +112,10 @@ re_parse_char_class (re_parser_ctx_t *, re_char_class_callback, void *, re_token
ecma_completion_value_t
re_parse_next_token (re_parser_ctx_t *, re_token_t *);
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* RE_PARSER_H */
/**
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* !RE_PARSER_H */
-217
View File
@@ -1,217 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "opcodes.h"
#include "opcodes-ecma-support.h"
/**
* 'Jump down if true' opcode handler.
*
* Note:
* current instruction's position changes by adding specified offset
* if argument evaluates to true.
*/
ecma_completion_value_t
opfunc_is_true_jmp_down (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t cond_var_idx = instr.data.is_true_jmp_down.value;
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_true_jmp_down.oc_idx_1,
instr.data.is_true_jmp_down.oc_idx_2);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
if (ecma_is_completion_value_normal_true (to_bool_completion))
{
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES);
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
}
else
{
frame_ctx_p->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
}
/* Likewise to opfunc_is_true_jmp_down, but jumps up. */
ecma_completion_value_t
opfunc_is_true_jmp_up (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t cond_var_idx = instr.data.is_true_jmp_up.value;
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_true_jmp_up.oc_idx_1,
instr.data.is_true_jmp_up.oc_idx_2);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
if (ecma_is_completion_value_normal_true (to_bool_completion))
{
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
}
else
{
frame_ctx_p->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
}
/**
* 'Jump down if false' opcode handler.
*
* Note:
* current instruction's position changes by adding specified offset
* if argument evaluates to false.
*/
ecma_completion_value_t
opfunc_is_false_jmp_down (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t cond_var_idx = instr.data.is_false_jmp_down.value;
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_false_jmp_down.oc_idx_1,
instr.data.is_false_jmp_down.oc_idx_2);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
if (!ecma_is_completion_value_normal_true (to_bool_completion))
{
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES);
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
}
else
{
frame_ctx_p->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
}
/* Likewise to opfunc_is_false_jmp_down, but jumps up. */
ecma_completion_value_t
opfunc_is_false_jmp_up (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t cond_var_idx = instr.data.is_false_jmp_up.value;
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.is_false_jmp_up.oc_idx_1,
instr.data.is_false_jmp_up.oc_idx_2);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (cond_value, get_variable_value (frame_ctx_p, cond_var_idx, false), ret_value);
ecma_completion_value_t to_bool_completion = ecma_op_to_boolean (cond_value);
JERRY_ASSERT (ecma_is_completion_value_normal (to_bool_completion));
if (!ecma_is_completion_value_normal_true (to_bool_completion))
{
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
}
else
{
frame_ctx_p->pos++;
}
ret_value = ecma_make_empty_completion_value ();
ECMA_FINALIZE (cond_value);
return ret_value;
}
/**
* 'Jump down' opcode handler.
*
* Note:
* the opcode changes adds specified value to current instruction position
*/
ecma_completion_value_t
opfunc_jmp_down (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.jmp_down.oc_idx_1,
instr.data.jmp_down.oc_idx_2);
JERRY_ASSERT (((uint32_t) frame_ctx_p->pos + offset < MAX_OPCODES));
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos + offset);
return ecma_make_empty_completion_value ();
}
/**
* 'Jump up' opcode handler.
*
* Note:
* the opcode changes substracts specified value from current instruction position
*/
ecma_completion_value_t
opfunc_jmp_up (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_instr_counter_t offset = vm_calc_instr_counter_from_idx_idx (instr.data.jmp_up.oc_idx_1,
instr.data.jmp_up.oc_idx_2);
JERRY_ASSERT ((uint32_t) frame_ctx_p->pos >= offset);
frame_ctx_p->pos = (vm_instr_counter_t) (frame_ctx_p->pos - offset);
return ecma_make_empty_completion_value ();
}
/**
* 'Break or continue jump' opcode handler.
*
* Note:
* the opcode returns break-continue completion value with jump target
*/
ecma_completion_value_t
opfunc_jmp_break_continue (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
vm_instr_counter_t target = frame_ctx_p->pos;
target = (vm_instr_counter_t) (target + vm_calc_instr_counter_from_idx_idx (instr.data.jmp_down.oc_idx_1,
instr.data.jmp_down.oc_idx_2));
return ecma_make_jump_completion_value (target);
} /* opfunc_jmp_break_continue */
+41 -215
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,22 +14,20 @@
* limitations under the License.
*/
#include "opcodes.h"
#include "opcodes-ecma-support.h"
#include "ecma-alloc.h"
#include "ecma-conversion.h"
#include "ecma-helpers.h"
#include "ecma-number-arithmetic.h"
#include "ecma-try-catch-macro.h"
#include "opcodes.h"
#include "jrt-libc-includes.h"
/**
* Number arithmetic operations.
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_opcodes Opcodes
* @{
*/
typedef enum
{
number_arithmetic_addition, /**< addition */
number_arithmetic_substraction, /**< substraction */
number_arithmetic_multiplication, /**< multiplication */
number_arithmetic_division, /**< division */
number_arithmetic_remainder, /**< remainder calculation */
} number_arithmetic_op;
/**
* Perform ECMA number arithmetic operation.
@@ -41,52 +40,48 @@ typedef enum
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
do_number_arithmetic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
vm_idx_t dst_var_idx, /**< destination variable identifier */
number_arithmetic_op op, /**< number arithmetic operation */
ecma_completion_value_t
do_number_arithmetic (number_arithmetic_op op, /**< number arithmetic operation */
ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /** right value */
ecma_value_t right_value) /**< right value */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
ecma_number_t *res_p = frame_ctx_p->tmp_num_p;
ecma_number_t *res_p = ecma_alloc_number ();
switch (op)
{
case number_arithmetic_addition:
case NUMBER_ARITHMETIC_ADDITION:
{
*res_p = ecma_number_add (num_left, num_right);
break;
}
case number_arithmetic_substraction:
case NUMBER_ARITHMETIC_SUBSTRACTION:
{
*res_p = ecma_number_substract (num_left, num_right);
break;
}
case number_arithmetic_multiplication:
case NUMBER_ARITHMETIC_MULTIPLICATION:
{
*res_p = ecma_number_multiply (num_left, num_right);
break;
}
case number_arithmetic_division:
case NUMBER_ARITHMETIC_DIVISION:
{
*res_p = ecma_number_divide (num_left, num_right);
break;
}
case number_arithmetic_remainder:
case NUMBER_ARITHMETIC_REMAINDER:
{
*res_p = ecma_op_number_remainder (num_left, num_right);
break;
}
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
dst_var_idx,
ecma_make_number_value (res_p));
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (res_p));
ECMA_OP_TO_NUMBER_FINALIZE (num_right);
ECMA_OP_TO_NUMBER_FINALIZE (num_left);
@@ -103,17 +98,11 @@ do_number_arithmetic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_addition (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_addition (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.addition.dst;
const vm_idx_t left_var_idx = instr.data.addition.var_left;
const vm_idx_t right_var_idx = instr.data.addition.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (prim_left_value,
ecma_op_to_primitive (left_value,
ECMA_PREFERRED_TYPE_NO),
@@ -134,172 +123,24 @@ opfunc_addition (vm_instr_t instr, /**< instruction */
ecma_string_t *concat_str_p = ecma_concat_ecma_strings (string1_p, string2_p);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_string_value (concat_str_p));
ecma_deref_ecma_string (concat_str_p);
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_string_value (concat_str_p));
ECMA_FINALIZE (str_right_value);
ECMA_FINALIZE (str_left_value);
}
else
{
ret_value = do_number_arithmetic (frame_ctx_p,
dst_var_idx,
number_arithmetic_addition,
prim_left_value,
prim_right_value);
ret_value = do_number_arithmetic (NUMBER_ARITHMETIC_ADDITION,
left_value,
right_value);
}
ECMA_FINALIZE (prim_right_value);
ECMA_FINALIZE (prim_left_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_addition */
/**
* 'Substraction' opcode handler.
*
* See also: ECMA-262 v5, 11.6.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_substraction (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.substraction.dst;
const vm_idx_t left_var_idx = instr.data.substraction.var_left;
const vm_idx_t right_var_idx = instr.data.substraction.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_arithmetic (frame_ctx_p,
dst_var_idx,
number_arithmetic_substraction,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_substraction */
/**
* 'Multiplication' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_multiplication (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.multiplication.dst;
const vm_idx_t left_var_idx = instr.data.multiplication.var_left;
const vm_idx_t right_var_idx = instr.data.multiplication.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_arithmetic (frame_ctx_p,
dst_var_idx,
number_arithmetic_multiplication,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_multiplication */
/**
* 'Division' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_division (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.division.dst;
const vm_idx_t left_var_idx = instr.data.division.var_left;
const vm_idx_t right_var_idx = instr.data.division.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_arithmetic (frame_ctx_p,
dst_var_idx,
number_arithmetic_division,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_division */
/**
* 'Remainder calculation' opcode handler.
*
* See also: ECMA-262 v5, 11.5, 11.5.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_remainder (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
const vm_idx_t left_var_idx = instr.data.remainder.var_left;
const vm_idx_t right_var_idx = instr.data.remainder.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_arithmetic (frame_ctx_p,
dst_var_idx,
number_arithmetic_remainder,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_remainder */
/**
* 'Unary "+"' opcode handler.
*
@@ -309,30 +150,20 @@ opfunc_remainder (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_unary_plus (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_unary_plus (ecma_value_t left_value) /**< left value */
{
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
const vm_idx_t var_idx = instr.data.remainder.var_left;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (var_value, get_variable_value (frame_ctx_p, var_idx, false), ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
var_value,
left_value,
ret_value);
ecma_number_t *tmp_p = frame_ctx_p->tmp_num_p;
ecma_number_t *tmp_p = ecma_alloc_number ();
*tmp_p = num_var_value;
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
dst_var_idx,
ecma_make_number_value (tmp_p));
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (tmp_p));
ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
ECMA_FINALIZE (var_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_unary_plus */
@@ -346,30 +177,25 @@ opfunc_unary_plus (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_unary_minus (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_unary_minus (ecma_value_t left_value) /**< left value */
{
const vm_idx_t dst_var_idx = instr.data.remainder.dst;
const vm_idx_t var_idx = instr.data.remainder.var_left;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (var_value, get_variable_value (frame_ctx_p, var_idx, false), ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (num_var_value,
var_value,
left_value,
ret_value);
ecma_number_t *tmp_p = frame_ctx_p->tmp_num_p;
ecma_number_t *tmp_p = ecma_alloc_number ();
*tmp_p = ecma_number_negate (num_var_value);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
dst_var_idx,
ecma_make_number_value (tmp_p));
ret_value = ecma_make_completion_value (ECMA_COMPLETION_TYPE_NORMAL, ecma_make_number_value (tmp_p));
ECMA_OP_TO_NUMBER_FINALIZE (num_var_value);
ECMA_FINALIZE (var_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_unary_minus */
/**
* @}
* @}
*/
+24 -269
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,22 +14,18 @@
* limitations under the License.
*/
#include "ecma-alloc.h"
#include "ecma-conversion.h"
#include "ecma-helpers.h"
#include "ecma-try-catch-macro.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
/**
* Number bitwise logic operations.
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_opcodes Opcodes
* @{
*/
typedef enum
{
number_bitwise_logic_and, /**< bitwise AND calculation */
number_bitwise_logic_or, /**< bitwise OR calculation */
number_bitwise_logic_xor, /**< bitwise XOR calculation */
number_bitwise_shift_left, /**< bitwise LEFT SHIFT calculation */
number_bitwise_shift_right, /**< bitwise RIGHT_SHIFT calculation */
number_bitwise_shift_uright, /**< bitwise UNSIGNED RIGHT SHIFT calculation */
number_bitwise_not, /**< bitwise NOT calculation */
} number_bitwise_logic_op;
/**
* Perform ECMA number logic operation.
@@ -41,10 +38,8 @@ typedef enum
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
static ecma_completion_value_t
do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
vm_idx_t dst_var_idx, /**< destination variable identifier */
number_bitwise_logic_op op, /**< number bitwise logic operation */
ecma_completion_value_t
do_number_bitwise_logic (number_bitwise_logic_op op, /**< number bitwise logic operation */
ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /** right value */
{
@@ -53,56 +48,53 @@ do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context *
ECMA_OP_TO_NUMBER_TRY_CATCH (num_left, left_value, ret_value);
ECMA_OP_TO_NUMBER_TRY_CATCH (num_right, right_value, ret_value);
ecma_number_t* res_p = frame_ctx_p->tmp_num_p;
ecma_number_t* res_p = ecma_alloc_number ();
int32_t left_int32 = ecma_number_to_int32 (num_left);
// int32_t right_int32 = ecma_number_to_int32 (num_right);
uint32_t left_uint32 = ecma_number_to_uint32 (num_left);
uint32_t right_uint32 = ecma_number_to_uint32 (num_right);
switch (op)
{
case number_bitwise_logic_and:
case NUMBER_BITWISE_LOGIC_AND:
{
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 & right_uint32));
break;
}
case number_bitwise_logic_or:
case NUMBER_BITWISE_LOGIC_OR:
{
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 | right_uint32));
break;
}
case number_bitwise_logic_xor:
case NUMBER_BITWISE_LOGIC_XOR:
{
*res_p = ecma_int32_to_number ((int32_t) (left_uint32 ^ right_uint32));
break;
}
case number_bitwise_shift_left:
case NUMBER_BITWISE_SHIFT_LEFT:
{
*res_p = ecma_int32_to_number (left_int32 << (right_uint32 & 0x1F));
break;
}
case number_bitwise_shift_right:
case NUMBER_BITWISE_SHIFT_RIGHT:
{
*res_p = ecma_int32_to_number (left_int32 >> (right_uint32 & 0x1F));
break;
}
case number_bitwise_shift_uright:
case NUMBER_BITWISE_SHIFT_URIGHT:
{
*res_p = ecma_uint32_to_number (left_uint32 >> (right_uint32 & 0x1F));
break;
}
case number_bitwise_not:
case NUMBER_BITWISE_NOT:
{
*res_p = ecma_int32_to_number ((int32_t) ~right_uint32);
break;
}
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
dst_var_idx,
ecma_make_number_value (res_p));
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (res_p));
ECMA_OP_TO_NUMBER_FINALIZE (num_right);
ECMA_OP_TO_NUMBER_FINALIZE (num_left);
@@ -111,243 +103,6 @@ do_number_bitwise_logic (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context *
} /* do_number_bitwise_logic */
/**
* 'Bitwise AND' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
* @}
* @}
*/
ecma_completion_value_t
opfunc_b_and (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_and.dst;
const vm_idx_t left_var_idx = instr.data.b_and.var_left;
const vm_idx_t right_var_idx = instr.data.b_and.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_logic_and,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_and */
/**
* 'Bitwise OR' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_or (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_or.dst;
const vm_idx_t left_var_idx = instr.data.b_or.var_left;
const vm_idx_t right_var_idx = instr.data.b_or.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_logic_or,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_or */
/**
* 'Bitwise XOR' opcode handler.
*
* See also: ECMA-262 v5, 11.10
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_xor (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_xor.dst;
const vm_idx_t left_var_idx = instr.data.b_xor.var_left;
const vm_idx_t right_var_idx = instr.data.b_xor.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_logic_xor,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_xor */
/**
* 'Left Shift Operator' opcode handler.
*
* See also: ECMA-262 v5, 11.7.1
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_shift_left (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_shift_left.dst;
const vm_idx_t left_var_idx = instr.data.b_shift_left.var_left;
const vm_idx_t right_var_idx = instr.data.b_shift_left.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_shift_left,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_shift_left */
/**
* 'Right Shift Operator' opcode handler.
*
* See also: ECMA-262 v5, 11.7.2
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_shift_right (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_shift_right.dst;
const vm_idx_t left_var_idx = instr.data.b_shift_right.var_left;
const vm_idx_t right_var_idx = instr.data.b_shift_right.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_shift_right,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_shift_right */
/**
* 'Unsigned Right Shift Operator' opcode handler.
*
* See also: ECMA-262 v5, 11.7.3
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_shift_uright (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_shift_uright.dst;
const vm_idx_t left_var_idx = instr.data.b_shift_uright.var_left;
const vm_idx_t right_var_idx = instr.data.b_shift_uright.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_shift_uright,
left_value,
right_value);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_shift_uright */
/**
* 'Bitwise NOT Operator' opcode handler.
*
* See also: ECMA-262 v5, 10.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_b_not (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t dst_var_idx = instr.data.b_not.dst;
const vm_idx_t right_var_idx = instr.data.b_not.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ret_value = do_number_bitwise_logic (frame_ctx_p,
dst_var_idx,
number_bitwise_not,
right_value,
right_value);
ECMA_FINALIZE (right_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_b_not */
+38 -74
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,8 +14,23 @@
* limitations under the License.
*/
#include "ecma-builtins.h"
#include "ecma-comparison.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-globals.h"
#include "ecma-helpers.h"
#include "ecma-lex-env.h"
#include "ecma-try-catch-macro.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
#include "vm-defines.h"
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_opcodes Opcodes
* @{
*/
/**
* 'Equals' opcode handler.
@@ -25,17 +41,11 @@
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_equal_value (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_equal_value (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.equal_value.dst;
const vm_idx_t left_var_idx = instr.data.equal_value.var_left;
const vm_idx_t right_var_idx = instr.data.equal_value.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_equality_compare (left_value,
right_value),
@@ -43,14 +53,9 @@ opfunc_equal_value (vm_instr_t instr, /**< instruction */
JERRY_ASSERT (ecma_is_value_boolean (compare_result));
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
compare_result);
ret_value = ecma_make_normal_completion_value (compare_result);
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_equal_value */
@@ -64,17 +69,11 @@ opfunc_equal_value (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_not_equal_value (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.not_equal_value.dst;
const vm_idx_t left_var_idx = instr.data.not_equal_value.var_left;
const vm_idx_t right_var_idx = instr.data.not_equal_value.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_equality_compare (left_value, right_value),
ret_value);
@@ -83,15 +82,10 @@ opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
bool is_equal = ecma_is_value_true (compare_result);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_not_equal_value */
@@ -105,30 +99,13 @@ opfunc_not_equal_value (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_equal_value_type (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_equal_value_type (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.equal_value_type.dst;
const vm_idx_t left_var_idx = instr.data.equal_value_type.var_left;
const vm_idx_t right_var_idx = instr.data.equal_value_type.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
return ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_TRUE
: ECMA_SIMPLE_VALUE_FALSE));
} /* opfunc_equal_value_type */
/**
@@ -140,29 +117,16 @@ opfunc_equal_value_type (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_not_equal_value_type (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_not_equal_value_type (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.not_equal_value_type.dst;
const vm_idx_t left_var_idx = instr.data.not_equal_value_type.var_left;
const vm_idx_t right_var_idx = instr.data.not_equal_value_type.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
bool is_equal = ecma_op_strict_equality_compare (left_value, right_value);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx,
ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
return ecma_make_normal_completion_value (ecma_make_simple_value (is_equal ? ECMA_SIMPLE_VALUE_FALSE
: ECMA_SIMPLE_VALUE_TRUE));
} /* opfunc_not_equal_value_type */
/**
* @}
* @}
*/
+38 -86
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,8 +14,20 @@
* limitations under the License.
*/
#include "ecma-comparison.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-helpers.h"
#include "ecma-objects.h"
#include "ecma-try-catch-macro.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_opcodes Opcodes
* @{
*/
/**
* 'Less-than' opcode handler.
@@ -25,17 +38,11 @@
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_less_than (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_less_than (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.less_than.dst;
const vm_idx_t left_var_idx = instr.data.less_than.var_left;
const vm_idx_t right_var_idx = instr.data.less_than.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_relational_compare (left_value, right_value, true),
ret_value);
@@ -53,13 +60,9 @@ opfunc_less_than (vm_instr_t instr, /**< instruction */
res = (ecma_is_value_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE);
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
ret_value = ecma_make_simple_completion_value (res);
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_less_than */
@@ -73,17 +76,11 @@ opfunc_less_than (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_greater_than (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_greater_than (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.greater_than.dst;
const vm_idx_t left_var_idx = instr.data.greater_than.var_left;
const vm_idx_t right_var_idx = instr.data.greater_than.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_relational_compare (right_value, left_value, false),
ret_value);
@@ -101,13 +98,9 @@ opfunc_greater_than (vm_instr_t instr, /**< instruction */
res = (ecma_is_value_true (compare_result) ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE);
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
ret_value = ecma_make_simple_completion_value (res);
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_greater_than */
@@ -121,17 +114,11 @@ opfunc_greater_than (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_less_or_equal_than (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.less_or_equal_than.dst;
const vm_idx_t left_var_idx = instr.data.less_or_equal_than.var_left;
const vm_idx_t right_var_idx = instr.data.less_or_equal_than.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_relational_compare (right_value, left_value, false),
ret_value);
@@ -156,13 +143,9 @@ opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
}
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
ret_value = ecma_make_simple_completion_value (res);
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_less_or_equal_than */
@@ -176,17 +159,11 @@ opfunc_less_or_equal_than (vm_instr_t instr, /**< instruction */
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
opfunc_greater_or_equal_than (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_var_idx = instr.data.greater_or_equal_than.dst;
const vm_idx_t left_var_idx = instr.data.greater_or_equal_than.var_left;
const vm_idx_t right_var_idx = instr.data.greater_or_equal_than.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
ECMA_TRY_CATCH (compare_result,
ecma_op_abstract_relational_compare (left_value, right_value, true),
ret_value);
@@ -211,13 +188,9 @@ opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
}
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_var_idx, ecma_make_simple_value (res));
ret_value = ecma_make_simple_completion_value (res);
ECMA_FINALIZE (compare_result);
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_greater_or_equal_than */
@@ -231,18 +204,11 @@ opfunc_greater_or_equal_than (vm_instr_t instr, /**< instruction */
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
opfunc_instanceof (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_idx = instr.data.instanceof.dst;
const vm_idx_t left_var_idx = instr.data.instanceof.var_left;
const vm_idx_t right_var_idx = instr.data.instanceof.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
if (!ecma_is_value_object (right_value))
{
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
@@ -255,16 +221,11 @@ opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
ecma_op_object_has_instance (right_value_obj_p, left_value),
ret_value);
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos, dst_idx, is_instance_of);
ret_value = ecma_make_normal_completion_value (is_instance_of);
ECMA_FINALIZE (is_instance_of);
}
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_instanceof */
@@ -277,18 +238,11 @@ opfunc_instanceof (vm_instr_t instr __attr_unused___, /**< instruction */
* returned value must be freed with ecma_free_completion_value.
*/
ecma_completion_value_t
opfunc_in (vm_instr_t instr __attr_unused___, /**< instruction */
vm_frame_ctx_t *frame_ctx_p __attr_unused___) /**< interpreter context */
opfunc_in (ecma_value_t left_value, /**< left value */
ecma_value_t right_value) /**< right value */
{
const vm_idx_t dst_idx = instr.data.in.dst;
const vm_idx_t left_var_idx = instr.data.in.var_left;
const vm_idx_t right_var_idx = instr.data.in.var_right;
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ECMA_TRY_CATCH (left_value, get_variable_value (frame_ctx_p, left_var_idx, false), ret_value);
ECMA_TRY_CATCH (right_value, get_variable_value (frame_ctx_p, right_var_idx, false), ret_value);
if (!ecma_is_value_object (right_value))
{
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
@@ -310,17 +264,15 @@ opfunc_in (vm_instr_t instr __attr_unused___, /**< instruction */
is_in = ECMA_SIMPLE_VALUE_FALSE;
}
ret_value = set_variable_value (frame_ctx_p, frame_ctx_p->pos,
dst_idx,
ecma_make_simple_value (is_in));
ret_value = ecma_make_simple_completion_value (is_in);
ECMA_FINALIZE (str_left_value);
}
ECMA_FINALIZE (right_value);
ECMA_FINALIZE (left_value);
frame_ctx_p->pos++;
return ret_value;
} /* opfunc_in */
/**
* @}
* @}
*/
-48
View File
@@ -1,48 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef OPCODES_ECMA_SUPPORT_H
#define OPCODES_ECMA_SUPPORT_H
#include "ecma-alloc.h"
#include "ecma-array-object.h"
#include "ecma-builtins.h"
#include "ecma-comparison.h"
#include "ecma-conversion.h"
#include "ecma-exceptions.h"
#include "ecma-function-object.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "ecma-lex-env.h"
#include "ecma-number-arithmetic.h"
#include "ecma-objects.h"
#include "ecma-objects-general.h"
#include "ecma-reference.h"
#include "ecma-regexp-object.h"
#include "ecma-try-catch-macro.h"
bool vm_is_reg_variable (vm_idx_t);
ecma_completion_value_t get_variable_value (vm_frame_ctx_t *, vm_idx_t, bool);
ecma_completion_value_t set_variable_value (vm_frame_ctx_t *, vm_instr_counter_t, vm_idx_t, ecma_value_t);
ecma_completion_value_t vm_fill_varg_list (vm_frame_ctx_t *, ecma_length_t, ecma_collection_header_t *);
extern vm_instr_counter_t vm_fill_params_list (const bytecode_data_header_t *,
vm_instr_counter_t,
ecma_length_t,
ecma_collection_header_t *);
extern ecma_completion_value_t vm_function_declaration (const bytecode_data_header_t *bytecode_header_p,
bool is_strict,
bool is_eval_code,
ecma_object_t *lex_env_p);
#endif /* OPCODES_ECMA_SUPPORT_H */
@@ -1,134 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "jrt.h"
#include "vm.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
/**
* 'Try' opcode handler.
*
* See also: ECMA-262 v5, 12.14
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_try_block (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */
{
const vm_idx_t block_end_oc_idx_1 = instr.data.try_block.oc_idx_1;
const vm_idx_t block_end_oc_idx_2 = instr.data.try_block.oc_idx_2;
const vm_instr_counter_t try_end_oc = (vm_instr_counter_t) (
vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + frame_ctx_p->pos);
frame_ctx_p->pos++;
vm_run_scope_t run_scope_try = { frame_ctx_p->pos, try_end_oc };
ecma_completion_value_t try_completion = vm_loop (frame_ctx_p, &run_scope_try);
JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= try_end_oc)
|| (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == try_end_oc));
frame_ctx_p->pos = try_end_oc;
vm_instr_t next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
if (next_instr.data.meta.type == OPCODE_META_TYPE_CATCH)
{
const vm_instr_counter_t catch_end_oc = (vm_instr_counter_t) (
vm_read_instr_counter_from_meta (OPCODE_META_TYPE_CATCH,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos) + frame_ctx_p->pos);
frame_ctx_p->pos++;
if (ecma_is_completion_value_throw (try_completion))
{
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER);
lit_cpointer_t catch_exc_val_var_name_lit_cp = bc_get_literal_cp_by_uid (next_instr.data.meta.data_1,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
frame_ctx_p->pos++;
ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_cp (catch_exc_val_var_name_lit_cp);
ecma_object_t *old_env_p = frame_ctx_p->lex_env_p;
ecma_object_t *catch_env_p = ecma_create_decl_lex_env (old_env_p);
ecma_completion_value_t completion = ecma_op_create_mutable_binding (catch_env_p,
catch_exc_var_name_str_p,
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
completion = ecma_op_set_mutable_binding (catch_env_p,
catch_exc_var_name_str_p,
ecma_get_completion_value_value (try_completion),
false);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
ecma_deref_ecma_string (catch_exc_var_name_str_p);
frame_ctx_p->lex_env_p = catch_env_p;
ecma_free_completion_value (try_completion);
vm_run_scope_t run_scope_catch = { frame_ctx_p->pos, catch_end_oc };
try_completion = vm_loop (frame_ctx_p, &run_scope_catch);
frame_ctx_p->lex_env_p = old_env_p;
ecma_deref_object (catch_env_p);
JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= catch_end_oc)
|| (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == catch_end_oc));
}
frame_ctx_p->pos = catch_end_oc;
}
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
if (next_instr.data.meta.type == OPCODE_META_TYPE_FINALLY)
{
const vm_instr_counter_t finally_end_oc = (vm_instr_counter_t) (
vm_read_instr_counter_from_meta (OPCODE_META_TYPE_FINALLY,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos) + frame_ctx_p->pos);
frame_ctx_p->pos++;
vm_run_scope_t run_scope_finally = { frame_ctx_p->pos, finally_end_oc };
ecma_completion_value_t finally_completion = vm_loop (frame_ctx_p, &run_scope_finally);
JERRY_ASSERT ((!ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos <= finally_end_oc)
|| (ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos == finally_end_oc));
frame_ctx_p->pos = finally_end_oc;
if (!ecma_is_completion_value_empty (finally_completion))
{
ecma_free_completion_value (try_completion);
try_completion = finally_completion;
}
}
next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos++);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_END_TRY_CATCH_FINALLY);
return try_completion;
} /* opfunc_try_block */
-125
View File
@@ -1,125 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "jrt.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
/**
* 'for-in' opcode handler
*
* See also:
* ECMA-262 v5, 12.6.4
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
opfunc_for_in (vm_instr_t instr, /**< instruction */
vm_frame_ctx_t *int_data_p) /**< interpreter context */
{
const vm_idx_t expr_idx = instr.data.for_in.expr;
const vm_idx_t block_end_oc_idx_1 = instr.data.for_in.oc_idx_1;
const vm_idx_t block_end_oc_idx_2 = instr.data.for_in.oc_idx_2;
const vm_instr_counter_t for_in_end_oc = (vm_instr_counter_t) (
vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1,
block_end_oc_idx_2) + int_data_p->pos);
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
/* 1., 2. */
ECMA_TRY_CATCH (expr_value,
get_variable_value (int_data_p,
expr_idx,
false),
ret_value);
int_data_p->pos++;
vm_instr_t meta_instr = vm_get_instr (int_data_p->bytecode_header_p->instrs_p, for_in_end_oc);
JERRY_ASSERT (meta_instr.op_idx == VM_OP_META);
JERRY_ASSERT (meta_instr.data.meta.type == OPCODE_META_TYPE_END_FOR_IN);
/* 3. */
if (!ecma_is_value_undefined (expr_value)
&& !ecma_is_value_null (expr_value))
{
/* 4. */
ECMA_TRY_CATCH (obj_expr_value,
ecma_op_to_object (expr_value),
ret_value);
ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value);
ecma_collection_iterator_t names_iterator;
ecma_collection_header_t *names_p = ecma_op_object_get_property_names (obj_p, false, true, true);
if (names_p != NULL)
{
ecma_collection_iterator_init (&names_iterator, names_p);
const vm_instr_counter_t for_in_body_begin_oc = int_data_p->pos;
const vm_instr_counter_t for_in_body_end_oc = for_in_end_oc;
while (ecma_collection_iterator_next (&names_iterator))
{
ecma_value_t name_value = *names_iterator.current_value_p;
ecma_string_t *name_p = ecma_get_string_from_value (name_value);
if (ecma_op_object_get_property (obj_p, name_p) != NULL)
{
ecma_completion_value_t completion = set_variable_value (int_data_p,
int_data_p->pos,
VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME,
name_value);
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
vm_run_scope_t run_scope_for_in = { for_in_body_begin_oc, for_in_body_end_oc };
ecma_completion_value_t for_in_body_completion = vm_loop (int_data_p, &run_scope_for_in);
if (ecma_is_completion_value_empty (for_in_body_completion))
{
JERRY_ASSERT (int_data_p->pos == for_in_body_end_oc);
int_data_p->pos = for_in_body_begin_oc;
}
else
{
JERRY_ASSERT (ecma_is_completion_value_throw (for_in_body_completion)
|| ecma_is_completion_value_return (for_in_body_completion)
|| ecma_is_completion_value_jump (for_in_body_completion));
JERRY_ASSERT (int_data_p->pos <= for_in_body_end_oc);
ret_value = for_in_body_completion;
break;
}
}
}
ecma_free_values_collection (names_p, true);
}
ECMA_FINALIZE (obj_expr_value);
}
int_data_p->pos = (vm_instr_counter_t) (for_in_end_oc + 1u);
ECMA_FINALIZE (expr_value);
return ret_value;
} /* opfunc_for_in */
-181
View File
@@ -1,181 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "opcodes-ecma-support.h"
#ifndef JERRY_NDEBUG
/**
* Perform so-called 'strict eval or arguments reference' check
* that is used in definition of several statement handling algorithms,
* but has no ECMA-defined name.
*/
static void
do_strict_eval_arguments_check (ecma_object_t *ref_base_lex_env_p, /**< base of ECMA-reference
(lexical environment) */
ecma_string_t *var_name_string_p, /**< variable name */
bool is_strict) /**< flag indicating strict mode */
{
bool is_check_failed = false;
if (is_strict)
{
if (ref_base_lex_env_p != NULL)
{
JERRY_ASSERT (ecma_is_lexical_environment (ref_base_lex_env_p));
ecma_string_t* magic_string_eval = ecma_get_magic_string (LIT_MAGIC_STRING_EVAL);
ecma_string_t* magic_string_arguments = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS);
is_check_failed = (ecma_compare_ecma_strings (var_name_string_p,
magic_string_eval)
|| ecma_compare_ecma_strings (var_name_string_p,
magic_string_arguments));
ecma_deref_ecma_string (magic_string_eval);
ecma_deref_ecma_string (magic_string_arguments);
}
}
JERRY_ASSERT (!is_check_failed);
} /* do_strict_eval_arguments_check */
#endif /* !JERRY_NDEBUG */
/**
* Check if the variable is register variable.
*
* @return true - if var_idx is a register variable,
* false - otherwise.
*/
bool
vm_is_reg_variable (vm_idx_t var_idx) /**< variable identifier */
{
return (var_idx >= VM_REG_FIRST && var_idx <= VM_REG_LAST);
} /* vm_is_reg_variable */
/**
* Get variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
get_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
vm_idx_t var_idx, /**< variable identifier */
bool do_eval_or_arguments_check) /** run 'strict eval or arguments reference' check
See also: do_strict_eval_arguments_check */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
if (vm_is_reg_variable (var_idx))
{
ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, var_idx);
JERRY_ASSERT (!ecma_is_value_empty (reg_value));
ret_value = ecma_make_normal_completion_value (ecma_copy_value (reg_value, true));
}
else
{
ecma_string_t var_name_string;
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (var_idx,
frame_ctx_p->bytecode_header_p,
frame_ctx_p->pos);
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp);
ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
&var_name_string);
if (do_eval_or_arguments_check)
{
#ifndef JERRY_NDEBUG
do_strict_eval_arguments_check (ref_base_lex_env_p,
&var_name_string,
frame_ctx_p->is_strict);
#endif /* !JERRY_NDEBUG */
}
ret_value = ecma_op_get_value_lex_env_base (ref_base_lex_env_p,
&var_name_string,
frame_ctx_p->is_strict);
ecma_check_that_ecma_string_need_not_be_freed (&var_name_string);
}
return ret_value;
} /* get_variable_value */
/**
* Set variable's value.
*
* @return completion value
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
set_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
vm_instr_counter_t lit_oc, /**< instruction counter for literal */
vm_idx_t var_idx, /**< variable identifier */
ecma_value_t value) /**< value to set */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
if (vm_is_reg_variable (var_idx))
{
ret_value = ecma_make_empty_completion_value ();
ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, var_idx);
if (ecma_is_value_number (reg_value)
&& ecma_is_value_number (value))
{
*ecma_get_number_from_value (reg_value) = *ecma_get_number_from_value (value);
}
else
{
if (!ecma_is_value_empty (reg_value))
{
ecma_free_value (reg_value, false);
}
vm_stack_frame_set_reg_value (&frame_ctx_p->stack_frame, var_idx, ecma_copy_value (value, false));
}
}
else
{
ecma_string_t var_name_string;
lit_cpointer_t lit_cp = bc_get_literal_cp_by_uid (var_idx, frame_ctx_p->bytecode_header_p, lit_oc);
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
ecma_new_ecma_string_on_stack_from_lit_cp (&var_name_string, lit_cp);
ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p,
&var_name_string);
#ifndef JERRY_NDEBUG
do_strict_eval_arguments_check (ref_base_lex_env_p,
&var_name_string,
frame_ctx_p->is_strict);
#endif /* !JERRY_NDEBUG */
ret_value = ecma_op_put_value_lex_env_base (ref_base_lex_env_p,
&var_name_string,
frame_ctx_p->is_strict,
value);
ecma_check_that_ecma_string_need_not_be_freed (&var_name_string);
}
return ret_value;
} /* set_variable_value */
-109
View File
@@ -1,109 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "jrt.h"
#include "opcodes.h"
#include "opcodes-ecma-support.h"
#include "vm.h"
/**
* Fill arguments' list
*
* @return empty completion value if argument list was filled successfully,
* otherwise - not normal completion value indicating completion type
* of last expression evaluated
*/
ecma_completion_value_t
vm_fill_varg_list (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */
ecma_length_t args_number, /**< number of arguments */
ecma_collection_header_t *arg_collection_p) /** collection to fill with argument values */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
ecma_length_t arg_index;
for (arg_index = 0;
arg_index < args_number && ecma_is_completion_value_empty (ret_value);
arg_index++)
{
ECMA_TRY_CATCH (evaluate_arg,
vm_loop (frame_ctx_p, NULL),
ret_value);
vm_instr_t next_instr = vm_get_instr (frame_ctx_p->bytecode_header_p->instrs_p, frame_ctx_p->pos);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_VARG);
const vm_idx_t varg_var_idx = next_instr.data.meta.data_1;
ECMA_TRY_CATCH (get_arg,
get_variable_value (frame_ctx_p, varg_var_idx, false),
ret_value);
ecma_append_to_values_collection (arg_collection_p,
ecma_get_completion_value_value (get_arg_completion),
true);
ECMA_FINALIZE (get_arg);
frame_ctx_p->pos++;
ECMA_FINALIZE (evaluate_arg);
}
return ret_value;
} /* vm_fill_varg_list */
/**
* Fill parameters' list
*/
vm_instr_counter_t
vm_fill_params_list (const bytecode_data_header_t *bytecode_header_p, /**< header of byte-code */
vm_instr_counter_t first_instr_pos, /**< position of the first instruction
* with a formal parameter's name */
ecma_length_t params_number, /**< number of parameters */
ecma_collection_header_t *formal_params_collection_p) /**< collection to fill with
* parameters' names */
{
vm_instr_counter_t instr_pos = first_instr_pos;
uint32_t param_index;
for (param_index = 0;
param_index < params_number;
param_index++)
{
vm_instr_t next_instr = vm_get_instr (bytecode_header_p->instrs_p, instr_pos);
JERRY_ASSERT (next_instr.op_idx == VM_OP_META);
JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_VARG);
const lit_cpointer_t param_name_lit_idx = bc_get_literal_cp_by_uid (next_instr.data.meta.data_1,
bytecode_header_p,
instr_pos);
ecma_string_t *param_name_str_p = ecma_new_ecma_string_from_lit_cp (param_name_lit_idx);
ecma_value_t param_name_value = ecma_make_string_value (param_name_str_p);
ecma_append_to_values_collection (formal_params_collection_p, param_name_value, false);
ecma_deref_ecma_string (param_name_str_p);
instr_pos++;
}
JERRY_ASSERT (param_index == params_number);
return instr_pos;
} /* vm_fill_params_list */
+229 -1578
View File
File diff suppressed because it is too large Load Diff
+102 -266
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,284 +18,119 @@
#define OPCODES_H
#include "ecma-globals.h"
#include "jrt.h"
#include "vm-stack.h"
#include "vm-defines.h"
/* Maximum opcodes number in bytecode. */
#define MAX_OPCODES (256*256 - 1)
#define OP_0(action, name) \
__##action (name, void, void, void)
#define OP_1(action, name, field1) \
__##action (name, field1, void, void)
#define OP_2(action, name, field1, field2) \
__##action (name, field1, field2, void)
#define OP_3(action, name, field1, field2, field3) \
__##action (name, field1, field2, field3)
/**
* Instruction counter / position
*/
typedef uint16_t vm_instr_counter_t;
/**
* Opcode / argument value in an instruction ("idx")
*/
typedef uint8_t vm_idx_t;
/**
* Description of vm_idx_t possible value ranges and special values
*/
enum : vm_idx_t
{
VM_IDX_GENERAL_VALUE_FIRST = 0, /**< first idx value that can be used for any argument value */
VM_IDX_GENERAL_VALUE_LAST = 252, /**< last idx value that can be used for any argument value */
/*
* Special values
*/
VM_IDX_REWRITE_GENERAL_CASE = 253, /**< intermediate value, used during byte-code generation,
* indicating that the idx would be rewritten with a value
* other than in-block literal identifier */
VM_IDX_REWRITE_LITERAL_UID = 254, /**< intermediate value, used during byte-code generation,
* indicating that the idx would be rewritten with in-block
* literal identifier */
VM_IDX_EMPTY = 255, /**< empty idx value, used when corresponding instruction argument is not set */
/*
* Literals (variable names / strings / numbers) ranges
*/
VM_IDX_LITERAL_FIRST = VM_IDX_GENERAL_VALUE_FIRST, /**< index of first possible literals-related idx value */
VM_IDX_LITERAL_LAST = VM_IDX_LITERAL_FIRST + 127, /**< index of last possible literals-related idx value */
/*
* Registers (temp variables) ranges
*/
VM_IDX_REG_FIRST = VM_IDX_LITERAL_LAST + 1, /** identifier of first special register */
VM_IDX_REG_LAST = VM_IDX_GENERAL_VALUE_LAST, /**< identifier of last register */
};
/**
* Ranges of registers (temporary variables)
*/
typedef enum : vm_idx_t
{
VM_REG_FIRST = VM_IDX_REG_FIRST, /** first register */
VM_REG_LAST = VM_IDX_REG_LAST, /**< last register */
VM_REG_SPECIAL_FIRST = VM_REG_FIRST, /**< first special register */
VM_REG_SPECIAL_EVAL_RET = VM_REG_SPECIAL_FIRST, /**< eval return value */
VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME, /**< variable, containing property name,
* at start of for-in loop body */
VM_REG_SPECIAL_THIS_BINDING, /**< value of ThisBinding */
VM_REG_SPECIAL_LAST = VM_REG_SPECIAL_THIS_BINDING, /**< last special register */
VM_REG_GENERAL_FIRST, /** first non-special register */
VM_REG_GENERAL_LAST = VM_IDX_REG_LAST /** last non-special register */
} vm_reg_t;
/**
* Number of special VM registers
*/
#define VM_SPECIAL_REGS_NUMBER (VM_REG_SPECIAL_LAST - VM_REG_SPECIAL_FIRST + 1u)
/**
* Descriptor of assignment's second argument
* that specifies type of third argument.
*/
typedef enum
{
OPCODE_ARG_TYPE_SIMPLE, /**< ecma_simple_value_t */
OPCODE_ARG_TYPE_SMALLINT, /**< small integer: from 0 to 255 */
OPCODE_ARG_TYPE_SMALLINT_NEGATE, /**< small integer: from -255 to -0 */
OPCODE_ARG_TYPE_NUMBER, /**< index of number literal */
OPCODE_ARG_TYPE_NUMBER_NEGATE, /**< index of number literal with negation */
OPCODE_ARG_TYPE_STRING, /**< index of string literal */
OPCODE_ARG_TYPE_VARIABLE, /**< index of string literal with variable name */
OPCODE_ARG_TYPE_REGEXP /**< index of string literal with regular expression */
} opcode_arg_type_operand;
/**
* Types of data in 'meta' opcode.
*/
typedef enum
{
OPCODE_META_TYPE_UNDEFINED, /**< undefined meta (should be rewritten) */
OPCODE_META_TYPE_CALL_SITE_INFO, /**< optional additional information about call site
* (includes opcode_call_flags_t and can include 'this' argument) */
OPCODE_META_TYPE_VARG, /**< element (var_idx) of arguments' list */
OPCODE_META_TYPE_VARG_PROP_DATA, /**< name (lit_idx) and value (var_idx) for a data property descriptor */
OPCODE_META_TYPE_VARG_PROP_GETTER, /**< name (lit_idx) and getter (var_idx) for an accessor property descriptor */
OPCODE_META_TYPE_VARG_PROP_SETTER, /**< name (lit_idx) and setter (var_idx) for an accessor property descriptor */
OPCODE_META_TYPE_END_WITH, /**< end of with statement */
OPCODE_META_TYPE_FUNCTION_END, /**< offset to function end */
OPCODE_META_TYPE_CATCH, /**< mark of beginning of catch block containing pointer to end of catch block */
OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER, /**< literal index containing name of variable with exception object */
OPCODE_META_TYPE_FINALLY, /**< mark of beginning of finally block containing pointer to end of finally block */
OPCODE_META_TYPE_END_TRY_CATCH_FINALLY, /**< mark of end of try-catch, try-finally, try-catch-finally blocks */
OPCODE_META_TYPE_END_FOR_IN /**< end of for-in statement */
} opcode_meta_type;
typedef enum : vm_idx_t
{
OPCODE_CALL_FLAGS__EMPTY = (0u), /**< initializer for empty flag set */
OPCODE_CALL_FLAGS_HAVE_THIS_ARG = (1u << 0), /**< flag, indicating that call is performed
* with 'this' argument specified */
OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM = (1u << 1) /**< flag, indicating that call is performed
* in form 'eval (...)', i.e. through 'eval' string
* without object base (i.e. with lexical environment
* as base), so it can be a direct call to eval
* See also: ECMA-262 v5, 15.1.2.1.1
*/
} opcode_call_flags_t;
/**
* Types of byte-code instruction arguments, used for instruction description
/** \addtogroup vm Virtual machine
* @{
*
* See also:
* vm-opcodes.inc.h
* \addtogroup vm_opcodes Opcodes
* @{
*/
/**
* Number arithmetic operations.
*/
typedef enum
{
VM_OP_ARG_TYPE_EMPTY = (1u << 0), /**< empty argument (no value) */
VM_OP_ARG_TYPE_REGISTER = (1u << 1), /**< register variable (index) */
VM_OP_ARG_TYPE_IDENTIFIER = (1u << 2), /**< identifier - named variable (string literal) */
VM_OP_ARG_TYPE_STRING = (1u << 3), /**< string constant value (string literal) */
VM_OP_ARG_TYPE_NUMBER = (1u << 4), /**< number constant value (number literal) */
VM_OP_ARG_TYPE_INTEGER_CONST = (1u << 5), /**< a 8-bit integer constant (any vm_idx_t) */
VM_OP_ARG_TYPE_TYPE_OF_NEXT = (1u << 6), /**< opcode_arg_type_operand value,
* representing type of argument encoded in next idx */
/** variable - an identifier or a register */
VM_OP_ARG_TYPE_VARIABLE = (VM_OP_ARG_TYPE_REGISTER | VM_OP_ARG_TYPE_IDENTIFIER)
} vm_op_arg_type_t;
NUMBER_ARITHMETIC_ADDITION, /**< addition */
NUMBER_ARITHMETIC_SUBSTRACTION, /**< substraction */
NUMBER_ARITHMETIC_MULTIPLICATION, /**< multiplication */
NUMBER_ARITHMETIC_DIVISION, /**< division */
NUMBER_ARITHMETIC_REMAINDER, /**< remainder calculation */
} number_arithmetic_op;
/**
* Forward declaration of instruction structure
* Number bitwise logic operations.
*/
struct vm_instr_t;
/**
* Forward declaration of bytecode data header structure
*/
struct bytecode_data_header_t;
/**
* Context of interpreter, related to a JS stack frame
*/
typedef struct
{
const bytecode_data_header_t *bytecode_header_p; /**< currently executed byte-code data */
vm_instr_counter_t pos; /**< current position instruction to execute */
ecma_object_t *lex_env_p; /**< current lexical environment */
bool is_strict; /**< is current code execution mode strict? */
bool is_eval_code; /**< is current code executed with eval */
bool is_call_in_direct_eval_form; /** flag, indicating if there is call of 'Direct call to eval' form in
* process (see also: OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM) */
ecma_number_t *tmp_num_p; /**< an allocated number (to reduce temporary allocations) */
vm_stack_frame_t stack_frame; /**< stack frame associated with the context */
#ifdef MEM_STATS
size_t context_peak_allocated_heap_bytes;
size_t context_peak_waste_heap_bytes;
size_t context_peak_pools_count;
size_t context_peak_allocated_pool_chunks;
mem_heap_stats_t heap_stats_context_enter;
mem_pools_stats_t pools_stats_context_enter;
#endif /* MEM_STATS */
} vm_frame_ctx_t;
/**
* Description of a run scope
*
* Note:
* Run scope represents boundaries of byte-code block to run.
*
* Jumps within of the current run scope are performed by just changing instruction counter,
* and outside of the run scope - by returning corresponding ECMA_COMPLETION_TYPE_BREAK_CONTINUE
* completion value.
*/
typedef struct
{
const vm_instr_counter_t start_oc; /**< instruction counter of the first instruction of the scope */
const vm_instr_counter_t end_oc; /**< instruction counter of the last instruction of the scope */
} vm_run_scope_t;
vm_instr_counter_t vm_calc_instr_counter_from_idx_idx (const vm_idx_t, const vm_idx_t);
vm_instr_counter_t vm_read_instr_counter_from_meta (opcode_meta_type,
const bytecode_data_header_t *,
vm_instr_counter_t);
typedef struct vm_instr_t
{
vm_idx_t op_idx;
union
{
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
struct \
{ \
vm_idx_t arg1; \
} opcode_name;
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
struct \
{ \
vm_idx_t arg1; \
vm_idx_t arg2; \
} opcode_name;
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
struct \
{ \
vm_idx_t arg1; \
vm_idx_t arg2; \
vm_idx_t arg3; \
} opcode_name;
#include "vm-opcodes.inc.h"
/**
* Opcode-independent arguments accessor
*
* Note:
* If opcode is statically known, opcode-specific way of accessing arguments should be used.
*/
vm_idx_t raw_args[3];
} data;
} vm_instr_t;
typedef enum
{
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
VM_OP_ ## opcode_name_uppercase,
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
VM_OP_ ## opcode_name_uppercase,
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
VM_OP_ ## opcode_name_uppercase,
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
VM_OP_ ## opcode_name_uppercase,
NUMBER_BITWISE_LOGIC_AND, /**< bitwise AND calculation */
NUMBER_BITWISE_LOGIC_OR, /**< bitwise OR calculation */
NUMBER_BITWISE_LOGIC_XOR, /**< bitwise XOR calculation */
NUMBER_BITWISE_SHIFT_LEFT, /**< bitwise LEFT SHIFT calculation */
NUMBER_BITWISE_SHIFT_RIGHT, /**< bitwise RIGHT_SHIFT calculation */
NUMBER_BITWISE_SHIFT_URIGHT, /**< bitwise UNSIGNED RIGHT SHIFT calculation */
NUMBER_BITWISE_NOT, /**< bitwise NOT calculation */
} number_bitwise_logic_op;
#include "vm-opcodes.inc.h"
ecma_completion_value_t
vm_var_decl (vm_frame_ctx_t *, ecma_string_t *);
VM_OP__COUNT /**< number of opcodes */
} vm_op_t;
ecma_completion_value_t
opfunc_call_n (ecma_value_t,
ecma_value_t,
const ecma_value_t *,
ecma_length_t);
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
ecma_completion_value_t opfunc_##opcode_name (vm_instr_t, vm_frame_ctx_t *);
ecma_completion_value_t
opfunc_construct_n (ecma_value_t, uint8_t, ecma_value_t *);
#include "vm-opcodes.inc.h"
ecma_completion_value_t
opfunc_equal_value (ecma_value_t, ecma_value_t);
typedef ecma_completion_value_t (*opfunc) (vm_instr_t, vm_frame_ctx_t *);
ecma_completion_value_t
opfunc_not_equal_value (ecma_value_t, ecma_value_t);
#endif /* OPCODES_H */
ecma_completion_value_t
opfunc_equal_value_type (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_not_equal_value_type (ecma_value_t, ecma_value_t);
ecma_completion_value_t
do_number_arithmetic (number_arithmetic_op, ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_unary_plus (ecma_value_t);
ecma_completion_value_t
opfunc_unary_minus (ecma_value_t);
ecma_completion_value_t
do_number_bitwise_logic (number_bitwise_logic_op, ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_addition (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_less_than (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_greater_than (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_less_or_equal_than (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_greater_or_equal_than (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_in (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_instanceof (ecma_value_t, ecma_value_t);
ecma_completion_value_t
opfunc_logical_not (ecma_value_t);
ecma_completion_value_t
opfunc_typeof (ecma_value_t);
void
opfunc_set_accessor (bool, ecma_value_t, ecma_value_t, ecma_value_t);
ecma_completion_value_t
vm_op_delete_prop (ecma_value_t, ecma_value_t, bool);
ecma_completion_value_t
vm_op_delete_var (lit_cpointer_t, ecma_object_t *, bool);
ecma_collection_header_t *
opfunc_for_in (ecma_value_t, ecma_value_t *);
/**
* @}
* @}
*/
#endif /* !OPCODES_H */
-583
View File
@@ -1,583 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifdef JERRY_ENABLE_PRETTY_PRINTER
#include <stdarg.h>
#include "pretty-printer.h"
#include "jrt-libc-includes.h"
#include "lexer.h"
#include "ecma-helpers.h"
#include "ecma-globals.h"
#include "lit-literal.h"
static const char* opcode_names[] =
{
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
#opcode_name,
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
#opcode_name,
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
#opcode_name,
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
#opcode_name,
#include "vm-opcodes.inc.h"
};
static uint8_t opcode_sizes[] =
{
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
0,
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
1,
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
2,
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
3,
#include "vm-opcodes.inc.h"
};
const bytecode_data_header_t *bc_to_print_header_p = NULL;
static char buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
static void
clear_temp_buffer (void)
{
memset (buff, 0, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
}
static const char *
lit_cp_to_str (lit_cpointer_t cp)
{
lit_literal_t lit = lit_get_literal_by_cp (cp);
return lit_literal_to_str_internal_buf (lit);
}
static const char *
tmp_id_to_str (vm_idx_t id)
{
JERRY_ASSERT (id != VM_IDX_REWRITE_LITERAL_UID);
JERRY_ASSERT (id >= 128);
clear_temp_buffer ();
strncpy (buff, "tmp", 3);
if (id / 100 != 0)
{
buff[3] = (char) (id / 100 + '0');
buff[4] = (char) ((id % 100) / 10 + '0');
buff[5] = (char) (id % 10 + '0');
}
else if (id / 10 != 0)
{
buff[3] = (char) (id / 10 + '0');
buff[4] = (char) (id % 10 + '0');
}
else
{
buff[3] = (char) (id + '0');
}
return buff;
}
static const char *
var_to_str (vm_instr_t instr, lit_cpointer_t lit_ids[], vm_instr_counter_t oc, uint8_t current_arg)
{
JERRY_ASSERT (current_arg >= 1 && current_arg <= 3);
if (instr.data.raw_args[current_arg - 1] == VM_IDX_REWRITE_LITERAL_UID)
{
JERRY_ASSERT (lit_ids != NULL);
JERRY_ASSERT (lit_ids[current_arg - 1].packed_value != MEM_CP_NULL);
return lit_cp_to_str (lit_ids[current_arg - 1]);
}
else if (instr.data.raw_args[current_arg - 1] >= 128)
{
return tmp_id_to_str (instr.data.raw_args[current_arg - 1]);
}
else
{
return lit_cp_to_str (bc_get_literal_cp_by_uid (instr.data.raw_args[current_arg - 1],
bc_to_print_header_p,
oc));
}
}
static void
pp_printf (const char *format, vm_instr_t instr, lit_cpointer_t lit_ids[], vm_instr_counter_t oc, uint8_t start_arg)
{
uint8_t current_arg = start_arg;
JERRY_ASSERT (current_arg <= 3);
while (*format)
{
if (*format != '%')
{
jerry_port_putchar (*format);
format++;
continue;
}
format++;
switch (*format)
{
case 'd':
{
JERRY_ASSERT (current_arg >= 1 && current_arg <= 3);
printf ("%d", instr.data.raw_args[current_arg - 1]);
break;
}
case 's':
{
printf ("%s", var_to_str (instr, lit_ids, oc, current_arg));
break;
}
default:
{
jerry_port_putchar ('%');
continue;
}
}
current_arg++;
format++;
}
}
#define PP_OP(op_name, format) \
case op_name: pp_printf (format, opm.op, opm.lit_id, oc, 1); break;
#define VAR(i) var_to_str (opm.op, opm.lit_id, oc, i)
#define OC(i, j) __extension__({ vm_calc_instr_counter_from_idx_idx (opm.op.data.raw_args[i - 1], \
opm.op.data.raw_args[j - 1]); })
static int vargs_num = 0;
static int seen_vargs = 0;
static void
dump_asm (vm_instr_counter_t oc, vm_instr_t instr)
{
uint8_t i = 0;
uint8_t opcode_id = instr.op_idx;
printf ("%3d: %20s ", oc, opcode_names[opcode_id]);
for (i = 1; i <= opcode_sizes[opcode_id]; i++)
{
printf ("%4d ", instr.data.raw_args[i - 1]);
}
for (; i < 4; i++)
{
printf (" ");
}
}
void
pp_op_meta (const bytecode_data_header_t *bytecode_data_p,
vm_instr_counter_t oc,
op_meta opm,
bool rewrite)
{
bc_to_print_header_p = bytecode_data_p;
dump_asm (oc, opm.op);
printf (" // ");
switch (opm.op.op_idx)
{
PP_OP (VM_OP_ADDITION, "%s = %s + %s;");
PP_OP (VM_OP_SUBSTRACTION, "%s = %s - %s;");
PP_OP (VM_OP_DIVISION, "%s = %s / %s;");
PP_OP (VM_OP_MULTIPLICATION, "%s = %s * %s;");
PP_OP (VM_OP_REMAINDER, "%s = %s %% %s;");
PP_OP (VM_OP_UNARY_MINUS, "%s = -%s;");
PP_OP (VM_OP_UNARY_PLUS, "%s = +%s;");
PP_OP (VM_OP_B_SHIFT_LEFT, "%s = %s << %s;");
PP_OP (VM_OP_B_SHIFT_RIGHT, "%s = %s >> %s;");
PP_OP (VM_OP_B_SHIFT_URIGHT, "%s = %s >>> %s;");
PP_OP (VM_OP_B_AND, "%s = %s & %s;");
PP_OP (VM_OP_B_OR, "%s = %s | %s;");
PP_OP (VM_OP_B_XOR, "%s = %s ^ %s;");
PP_OP (VM_OP_B_NOT, "%s = ~ %s;");
PP_OP (VM_OP_LOGICAL_NOT, "%s = ! %s;");
PP_OP (VM_OP_EQUAL_VALUE, "%s = %s == %s;");
PP_OP (VM_OP_NOT_EQUAL_VALUE, "%s = %s != %s;");
PP_OP (VM_OP_EQUAL_VALUE_TYPE, "%s = %s === %s;");
PP_OP (VM_OP_NOT_EQUAL_VALUE_TYPE, "%s = %s !== %s;");
PP_OP (VM_OP_LESS_THAN, "%s = %s < %s;");
PP_OP (VM_OP_GREATER_THAN, "%s = %s > %s;");
PP_OP (VM_OP_LESS_OR_EQUAL_THAN, "%s = %s <= %s;");
PP_OP (VM_OP_GREATER_OR_EQUAL_THAN, "%s = %s >= %s;");
PP_OP (VM_OP_INSTANCEOF, "%s = %s instanceof %s;");
PP_OP (VM_OP_IN, "%s = %s in %s;");
PP_OP (VM_OP_POST_INCR, "%s = %s++;");
PP_OP (VM_OP_POST_DECR, "%s = %s--;");
PP_OP (VM_OP_PRE_INCR, "%s = ++%s;");
PP_OP (VM_OP_PRE_DECR, "%s = --%s;");
PP_OP (VM_OP_THROW_VALUE, "throw %s;");
PP_OP (VM_OP_REG_VAR_DECL, "%d tmp regs, %d local variable regs, %d argument variable regs");
PP_OP (VM_OP_VAR_DECL, "var %s;");
PP_OP (VM_OP_RETVAL, "return %s;");
PP_OP (VM_OP_RET, "ret;");
PP_OP (VM_OP_PROP_GETTER, "%s = %s[%s];");
PP_OP (VM_OP_PROP_SETTER, "%s[%s] = %s;");
PP_OP (VM_OP_DELETE_VAR, "%s = delete %s;");
PP_OP (VM_OP_DELETE_PROP, "%s = delete %s.%s;");
PP_OP (VM_OP_TYPEOF, "%s = typeof %s;");
PP_OP (VM_OP_WITH, "with (%s);");
PP_OP (VM_OP_FOR_IN, "for_in (%s);");
case VM_OP_IS_TRUE_JMP_UP: printf ("if (%s) goto %d;", VAR (1), oc - OC (2, 3)); break;
case VM_OP_IS_FALSE_JMP_UP: printf ("if (%s == false) goto %d;", VAR (1), oc - OC (2, 3)); break;
case VM_OP_IS_TRUE_JMP_DOWN: printf ("if (%s) goto %d;", VAR (1), oc + OC (2, 3)); break;
case VM_OP_IS_FALSE_JMP_DOWN: printf ("if (%s == false) goto %d;", VAR (1), oc + OC (2, 3)); break;
case VM_OP_JMP_UP: printf ("goto %d;", oc - OC (1, 2)); break;
case VM_OP_JMP_DOWN: printf ("goto %d;", oc + OC (1, 2)); break;
case VM_OP_JMP_BREAK_CONTINUE: printf ("goto_nested %d;", oc + OC (1, 2)); break;
case VM_OP_TRY_BLOCK: printf ("try (end: %d);", oc + OC (1, 2)); break;
case VM_OP_ASSIGNMENT:
{
printf ("%s = ", VAR (1));
switch (opm.op.data.assignment.type_value_right)
{
case OPCODE_ARG_TYPE_STRING: printf ("'%s': STRING;", VAR (3)); break;
case OPCODE_ARG_TYPE_NUMBER: printf ("%s: NUMBER;", VAR (3)); break;
case OPCODE_ARG_TYPE_NUMBER_NEGATE: printf ("-%s: NUMBER;", VAR (3)); break;
case OPCODE_ARG_TYPE_SMALLINT: printf ("%d: SMALLINT;", opm.op.data.assignment.value_right); break;
case OPCODE_ARG_TYPE_SMALLINT_NEGATE: printf ("-%d: SMALLINT;", opm.op.data.assignment.value_right); break;
case OPCODE_ARG_TYPE_VARIABLE: printf ("%s : TYPEOF(%s);", VAR (3), VAR (3)); break;
case OPCODE_ARG_TYPE_SIMPLE:
{
switch (opm.op.data.assignment.value_right)
{
case ECMA_SIMPLE_VALUE_NULL: printf ("null"); break;
case ECMA_SIMPLE_VALUE_FALSE: printf ("false"); break;
case ECMA_SIMPLE_VALUE_TRUE: printf ("true"); break;
case ECMA_SIMPLE_VALUE_UNDEFINED: printf ("undefined"); break;
case ECMA_SIMPLE_VALUE_ARRAY_HOLE: printf ("hole"); break;
default: JERRY_UNREACHABLE ();
}
printf (": SIMPLE;");
break;
}
}
break;
}
case VM_OP_CALL_N:
{
vargs_num = opm.op.data.call_n.arg_list;
seen_vargs = 0;
break;
}
case VM_OP_CONSTRUCT_N:
{
if (opm.op.data.construct_n.arg_list == 0)
{
pp_printf ("%s = new %s;", opm.op, opm.lit_id, oc, 1);
}
else
{
vargs_num = opm.op.data.construct_n.arg_list;
seen_vargs = 0;
}
break;
}
case VM_OP_FUNC_DECL_N:
{
if (opm.op.data.func_decl_n.arg_list == 0)
{
printf ("function %s ();", VAR (1));
}
else
{
vargs_num = opm.op.data.func_decl_n.arg_list;
seen_vargs = 0;
}
break;
}
case VM_OP_FUNC_EXPR_REF:
{
printf ("%s = function ();", VAR (1));
break;
}
case VM_OP_FUNC_EXPR_N:
{
if (opm.op.data.func_expr_n.arg_list == 0)
{
if (opm.op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY)
{
printf ("%s = function ();", VAR (1));
}
else
{
pp_printf ("%s = function %s ();", opm.op, opm.lit_id, oc, 1);
}
}
else
{
vargs_num = opm.op.data.func_expr_n.arg_list;
seen_vargs = 0;
}
break;
}
case VM_OP_ARRAY_DECL:
{
if (opm.op.data.array_decl.list_1 == 0
&& opm.op.data.array_decl.list_2 == 0)
{
printf ("%s = [];", VAR (1));
}
else
{
vargs_num = (((int) opm.op.data.array_decl.list_1 << JERRY_BITSINBYTE)
+ (int) opm.op.data.array_decl.list_2);
seen_vargs = 0;
}
break;
}
case VM_OP_OBJ_DECL:
{
if (opm.op.data.obj_decl.list_1 == 0
&& opm.op.data.obj_decl.list_2 == 0)
{
printf ("%s = {};", VAR (1));
}
else
{
vargs_num = (((int) opm.op.data.obj_decl.list_1 << JERRY_BITSINBYTE)
+ (int) opm.op.data.obj_decl.list_2);
seen_vargs = 0;
}
break;
}
case VM_OP_META:
{
switch (opm.op.data.meta.type)
{
case OPCODE_META_TYPE_UNDEFINED:
{
printf ("unknown meta;");
break;
}
case OPCODE_META_TYPE_CALL_SITE_INFO:
case OPCODE_META_TYPE_VARG:
case OPCODE_META_TYPE_VARG_PROP_DATA:
case OPCODE_META_TYPE_VARG_PROP_GETTER:
case OPCODE_META_TYPE_VARG_PROP_SETTER:
{
if (opm.op.data.meta.type != OPCODE_META_TYPE_CALL_SITE_INFO)
{
seen_vargs++;
}
if (seen_vargs == vargs_num)
{
bool found = false;
vm_instr_counter_t start = oc;
while ((int16_t) start >= 0 && !found)
{
start--;
switch (bc_get_instr (bytecode_data_p, start).op_idx)
{
case VM_OP_CALL_N:
case VM_OP_CONSTRUCT_N:
case VM_OP_FUNC_DECL_N:
case VM_OP_FUNC_EXPR_N:
case VM_OP_ARRAY_DECL:
case VM_OP_OBJ_DECL:
{
found = true;
break;
}
}
}
vm_instr_t start_op = bc_get_instr (bytecode_data_p, start);
switch (start_op.op_idx)
{
case VM_OP_CALL_N:
{
pp_printf ("%s = %s (", start_op, NULL, start, 1);
break;
}
case VM_OP_CONSTRUCT_N:
{
pp_printf ("%s = new %s (", start_op, NULL, start, 1);
break;
}
case VM_OP_FUNC_DECL_N:
{
pp_printf ("function %s (", start_op, NULL, start, 1);
break;
}
case VM_OP_FUNC_EXPR_N:
{
if (start_op.data.func_expr_n.name_lit_idx == VM_IDX_EMPTY)
{
pp_printf ("%s = function (", start_op, NULL, start, 1);
}
else
{
pp_printf ("%s = function %s (", start_op, NULL, start, 1);
}
break;
}
case VM_OP_ARRAY_DECL:
{
pp_printf ("%s = [", start_op, NULL, start, 1);
break;
}
case VM_OP_OBJ_DECL:
{
pp_printf ("%s = {", start_op, NULL, start, 1);
break;
}
default:
{
JERRY_UNREACHABLE ();
}
}
for (vm_instr_counter_t counter = start; counter <= oc; counter++)
{
vm_instr_t meta_op = bc_get_instr (bytecode_data_p, counter);
switch (meta_op.op_idx)
{
case VM_OP_META:
{
switch (meta_op.data.meta.type)
{
case OPCODE_META_TYPE_CALL_SITE_INFO:
{
opcode_call_flags_t call_flags = (opcode_call_flags_t) meta_op.data.meta.data_1;
if (call_flags & OPCODE_CALL_FLAGS_HAVE_THIS_ARG)
{
pp_printf ("this_arg = %s", meta_op, NULL, counter, 3);
}
if (call_flags & OPCODE_CALL_FLAGS_DIRECT_CALL_TO_EVAL_FORM)
{
printf ("['direct call to eval' form]");
}
break;
}
case OPCODE_META_TYPE_VARG:
{
pp_printf ("%s", meta_op, NULL, counter, 2);
break;
}
case OPCODE_META_TYPE_VARG_PROP_DATA:
{
pp_printf ("%s:%s", meta_op, NULL, counter, 2);
break;
}
case OPCODE_META_TYPE_VARG_PROP_GETTER:
{
pp_printf ("%s = get %s ();", meta_op, NULL, counter, 2);
break;
}
case OPCODE_META_TYPE_VARG_PROP_SETTER:
{
pp_printf ("%s = set (%s);", meta_op, NULL, counter, 2);
break;
}
default:
{
continue;
}
}
if (counter != oc)
{
printf (", ");
}
break;
}
}
}
switch (start_op.op_idx)
{
case VM_OP_ARRAY_DECL:
{
printf ("];");
break;
}
case VM_OP_OBJ_DECL:
{
printf ("};");
break;
}
default:
{
printf (");");
}
}
}
break;
}
case OPCODE_META_TYPE_END_WITH:
{
printf ("end with;");
break;
}
case OPCODE_META_TYPE_END_FOR_IN:
{
printf ("end for-in;");
break;
}
case OPCODE_META_TYPE_FUNCTION_END:
{
printf ("function end: %d;", oc + OC (2, 3));
break;
}
case OPCODE_META_TYPE_CATCH:
{
printf ("catch end: %d;", oc + OC (2, 3));
break;
}
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
{
printf ("catch (%s);", VAR (2));
break;
}
case OPCODE_META_TYPE_FINALLY:
{
printf ("finally end: %d;", oc + OC (2, 3));
break;
}
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
{
printf ("end try");
break;
}
default:
{
JERRY_UNREACHABLE ();
}
}
break;
}
default:
{
JERRY_UNREACHABLE ();
}
}
if (rewrite)
{
printf (" // REWRITE");
}
printf ("\n");
}
#endif /* JERRY_ENABLE_PRETTY_PRINTER */
-28
View File
@@ -1,28 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
#ifndef PRETTY_PRINTER
#define PRETTY_PRINTER
#include "jrt.h"
#ifdef JERRY_ENABLE_PRETTY_PRINTER
#include "bytecode-data.h"
#include "vm.h"
#include "scopes-tree.h"
void pp_op_meta (const bytecode_data_header_t *, vm_instr_counter_t, op_meta, bool);
#endif // JERRY_ENABLE_PRETTY_PRINTER
#endif // PRETTY_PRINTER
+61
View File
@@ -0,0 +1,61 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* 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.
*/
#ifndef VM_DEFINES_H
#define VM_DEFINES_H
#include "byte-code.h"
#include "ecma-globals.h"
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_executor Executor
* @{
*/
/**
* Helpers for updating uint16_t values.
*/
#define VM_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
#define VM_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
/**
* Instruction counter / position
*/
typedef const uint8_t *vm_instr_counter_t;
/**
* Context of interpreter, related to a JS stack frame
*/
typedef struct
{
const ecma_compiled_code_t *bytecode_header_p; /**< currently executed byte-code data */
uint8_t *byte_code_p; /**< current byte code pointer */
uint8_t *byte_code_start_p; /**< byte code start pointer */
ecma_value_t *registers_p; /**< register start pointer */
lit_cpointer_t *literal_start_p; /**< literal list start pointer */
ecma_object_t *lex_env_p; /**< current lexical environment */
ecma_value_t this_binding; /**< this binding */
uint16_t context_depth; /**< current context depth */
bool is_eval_code; /**< eval mode flag */
} vm_frame_ctx_t;
/**
* @}
* @}
*/
#endif /* !VM_DEFINES_H */
-317
View File
@@ -1,317 +0,0 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
*
* 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.
*/
/*
* List of VM opcodes
*/
#ifndef VM_OP_0
# define VM_OP_0(opcode_name, opcode_name_uppercase)
#endif /* !VM_OP_0 */
#ifndef VM_OP_1
# define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type)
#endif /* !VM_OP_1 */
#ifndef VM_OP_2
# define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type)
#endif /* !VM_OP_2 */
#ifndef VM_OP_3
# define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type)
#endif /* !VM_OP_3 */
VM_OP_3 (call_n, CALL_N,
lhs, VM_OP_ARG_TYPE_VARIABLE,
function_var_idx, VM_OP_ARG_TYPE_VARIABLE,
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (construct_n, CONSTRUCT_N,
lhs, VM_OP_ARG_TYPE_VARIABLE,
name_lit_idx, VM_OP_ARG_TYPE_VARIABLE,
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_2 (func_decl_n, FUNC_DECL_N,
name_lit_idx, VM_OP_ARG_TYPE_STRING,
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (func_expr_n, FUNC_EXPR_N,
lhs, VM_OP_ARG_TYPE_VARIABLE,
name_lit_idx, VM_OP_ARG_TYPE_STRING |
VM_OP_ARG_TYPE_EMPTY,
arg_list, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (func_expr_ref, FUNC_EXPR_REF,
lhs, VM_OP_ARG_TYPE_VARIABLE,
idx1, VM_OP_ARG_TYPE_INTEGER_CONST,
idx2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_1 (retval, RETVAL,
ret_value, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_0 (ret, RET)
VM_OP_3 (array_decl, ARRAY_DECL,
lhs, VM_OP_ARG_TYPE_VARIABLE,
list_1, VM_OP_ARG_TYPE_INTEGER_CONST,
list_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (obj_decl, OBJ_DECL,
lhs, VM_OP_ARG_TYPE_VARIABLE,
list_1, VM_OP_ARG_TYPE_INTEGER_CONST,
list_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (prop_getter, PROP_GETTER,
lhs, VM_OP_ARG_TYPE_VARIABLE,
obj, VM_OP_ARG_TYPE_VARIABLE,
prop, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (prop_setter, PROP_SETTER,
obj, VM_OP_ARG_TYPE_VARIABLE,
prop, VM_OP_ARG_TYPE_VARIABLE,
rhs, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (delete_var, DELETE_VAR,
lhs, VM_OP_ARG_TYPE_VARIABLE,
name, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (delete_prop, DELETE_PROP,
lhs, VM_OP_ARG_TYPE_VARIABLE,
base, VM_OP_ARG_TYPE_VARIABLE,
name, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (typeof, TYPEOF,
lhs, VM_OP_ARG_TYPE_VARIABLE,
obj, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (for_in, FOR_IN,
expr, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (with, WITH,
expr, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_2 (try_block, TRY_BLOCK,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_1 (throw_value, THROW_VALUE,
var, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (assignment, ASSIGNMENT,
var_left, VM_OP_ARG_TYPE_VARIABLE,
type_value_right, VM_OP_ARG_TYPE_TYPE_OF_NEXT,
value_right, VM_OP_ARG_TYPE_VARIABLE |
VM_OP_ARG_TYPE_STRING |
VM_OP_ARG_TYPE_NUMBER |
VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (b_shift_left, B_SHIFT_LEFT,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (b_shift_right, B_SHIFT_RIGHT,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (b_shift_uright, B_SHIFT_URIGHT,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (b_and, B_AND,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (b_or, B_OR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (b_xor, B_XOR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (b_not, B_NOT,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (logical_not, LOGICAL_NOT,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (equal_value, EQUAL_VALUE,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (not_equal_value, NOT_EQUAL_VALUE,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (equal_value_type, EQUAL_VALUE_TYPE,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (not_equal_value_type, NOT_EQUAL_VALUE_TYPE,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (less_than, LESS_THAN,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (greater_than, GREATER_THAN,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (less_or_equal_than, LESS_OR_EQUAL_THAN,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (greater_or_equal_than, GREATER_OR_EQUAL_THAN,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (instanceof, INSTANCEOF,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (in, IN,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (post_incr, POST_INCR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (post_decr, POST_DECR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (pre_incr, PRE_INCR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (pre_decr, PRE_DECR,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (addition, ADDITION,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (substraction, SUBSTRACTION,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (division, DIVISION,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (multiplication, MULTIPLICATION,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_3 (remainder, REMAINDER,
dst, VM_OP_ARG_TYPE_VARIABLE,
var_left, VM_OP_ARG_TYPE_VARIABLE,
var_right, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (unary_minus, UNARY_MINUS,
dst, VM_OP_ARG_TYPE_VARIABLE,
var, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (unary_plus, UNARY_PLUS,
dst, VM_OP_ARG_TYPE_VARIABLE,
var, VM_OP_ARG_TYPE_VARIABLE)
VM_OP_2 (jmp_up, JMP_UP,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_2 (jmp_down, JMP_DOWN,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_2 (jmp_break_continue, JMP_BREAK_CONTINUE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (is_true_jmp_up, IS_TRUE_JMP_UP,
value, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (is_true_jmp_down, IS_TRUE_JMP_DOWN,
value, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (is_false_jmp_up, IS_FALSE_JMP_UP,
value, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (is_false_jmp_down, IS_FALSE_JMP_DOWN,
value, VM_OP_ARG_TYPE_VARIABLE,
oc_idx_1, VM_OP_ARG_TYPE_INTEGER_CONST,
oc_idx_2, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_1 (var_decl, VAR_DECL,
variable_name, VM_OP_ARG_TYPE_STRING)
VM_OP_3 (reg_var_decl, REG_VAR_DECL,
tmp_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST,
local_var_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST,
arg_regs_num, VM_OP_ARG_TYPE_INTEGER_CONST)
VM_OP_3 (meta, META,
type, VM_OP_ARG_TYPE_INTEGER_CONST |
VM_OP_ARG_TYPE_TYPE_OF_NEXT,
data_1, VM_OP_ARG_TYPE_INTEGER_CONST |
VM_OP_ARG_TYPE_STRING |
VM_OP_ARG_TYPE_VARIABLE,
data_2, VM_OP_ARG_TYPE_INTEGER_CONST |
VM_OP_ARG_TYPE_VARIABLE)
#undef VM_OP_0
#undef VM_OP_1
#undef VM_OP_2
#undef VM_OP_3
+195 -253
View File
@@ -1,4 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,8 +14,10 @@
* limitations under the License.
*/
#include "ecma-globals.h"
#include "ecma-alloc.h"
#include "ecma-gc.h"
#include "ecma-helpers.h"
#include "vm-defines.h"
#include "vm-stack.h"
/** \addtogroup vm Virtual machine
@@ -25,287 +28,226 @@
*/
/**
* Size of a stack frame's dynamic chunk
*/
#define VM_STACK_DYNAMIC_CHUNK_SIZE (mem_heap_recommend_allocation_size (sizeof (vm_stack_chunk_header_t) + \
sizeof (ecma_value_t)))
/**
* Number of value slots in a stack frame's dynamic chunk
*/
#define VM_STACK_SLOTS_IN_DYNAMIC_CHUNK ((VM_STACK_DYNAMIC_CHUNK_SIZE - sizeof (vm_stack_chunk_header_t)) / \
sizeof (ecma_value_t))
/**
* The top-most stack frame
*/
vm_stack_frame_t* vm_stack_top_frame_p;
/**
* Initialize stack
*/
void
vm_stack_init (void)
{
vm_stack_top_frame_p = NULL;
} /* vm_stack_init */
/**
* Finalize stack
*/
void
vm_stack_finalize ()
{
JERRY_ASSERT (vm_stack_top_frame_p == NULL);
} /* vm_stack_finalize */
/**
* Get stack's top frame
* Abort (finalize) the current stack context, and remove it.
*
* @return pointer to the top frame descriptor
* @return new stack top
*/
vm_stack_frame_t*
vm_stack_get_top_frame (void)
ecma_value_t *
vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t *vm_stack_top_p) /**< current stack top */
{
return vm_stack_top_frame_p;
} /* vm_stack_get_top_frame */
/**
* Add the frame to stack
*/
void
vm_stack_add_frame (vm_stack_frame_t *frame_p, /**< frame to initialize */
ecma_value_t *regs_p, /**< array of register variables' values */
uint32_t regs_num, /**< total number of register variables */
uint32_t local_vars_regs_num, /**< number of register variables,
* used for local variables */
uint32_t arg_regs_num, /**< number of register variables,
* used for arguments */
ecma_collection_header_t *arguments_p) /**< collection of arguments
* (for case, their values
* are moved to registers) */
{
frame_p->prev_frame_p = vm_stack_top_frame_p;
vm_stack_top_frame_p = frame_p;
frame_p->top_chunk_p = NULL;
frame_p->dynamically_allocated_value_slots_p = frame_p->inlined_values;
frame_p->current_slot_index = 0;
frame_p->regs_p = regs_p;
frame_p->regs_number = regs_num;
JERRY_ASSERT (regs_num >= VM_SPECIAL_REGS_NUMBER);
for (uint32_t i = 0; i < regs_num - local_vars_regs_num - arg_regs_num; i++)
switch (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]))
{
regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY);
}
for (uint32_t i = regs_num - local_vars_regs_num - arg_regs_num;
i < regs_num;
i++)
{
regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED);
}
if (arg_regs_num != 0)
{
ecma_collection_iterator_t args_iterator;
ecma_collection_iterator_init (&args_iterator, arguments_p);
for (uint32_t i = regs_num - arg_regs_num;
i < regs_num && ecma_collection_iterator_next (&args_iterator);
i++)
case VM_CONTEXT_FINALLY_THROW:
case VM_CONTEXT_FINALLY_RETURN:
{
regs_p[i] = ecma_copy_value (*args_iterator.current_value_p, false);
ecma_free_value (vm_stack_top_p[-2], true);
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_FINALLY_JUMP:
case VM_CONTEXT_TRY:
{
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:
case VM_CONTEXT_WITH:
{
ecma_deref_object (frame_ctx_p->lex_env_p);
frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
JERRY_ASSERT (PARSER_TRY_CONTEXT_STACK_ALLOCATION == PARSER_WITH_CONTEXT_STACK_ALLOCATION);
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_FOR_IN:
{
mem_cpointer_t current = (uint16_t) vm_stack_top_p[-2];
while (current != MEM_CP_NULL)
{
ecma_collection_chunk_t *chunk_p = MEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t,
current);
ecma_free_value (*(ecma_value_t *) chunk_p->data, true);
current = chunk_p->next_chunk_cp;
ecma_dealloc_collection_chunk (chunk_p);
}
ecma_free_value (vm_stack_top_p[-3], true);
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;
break;
}
default:
{
JERRY_UNREACHABLE ();
break;
}
}
} /* vm_stack_add_frame */
return vm_stack_top_p;
} /* vm_stack_context_abort */
/**
* Free the stack frame
* Decode branch offset.
*
* Note:
* the frame should be the top-most frame
* @return branch offset
*/
void
vm_stack_free_frame (vm_stack_frame_t *frame_p) /**< frame to initialize */
static uint32_t
vm_decode_branch_offset (uint8_t *branch_offset_p, /**< start offset of byte code */
uint32_t length) /**< length of the branch */
{
/* the frame should be the top-most frame */
JERRY_ASSERT (vm_stack_top_frame_p == frame_p);
uint32_t branch_offset = *branch_offset_p;
vm_stack_top_frame_p = frame_p->prev_frame_p;
JERRY_ASSERT (length >= 1 && length <= 3);
while (frame_p->top_chunk_p != NULL)
switch (length)
{
vm_stack_pop (frame_p);
case 3:
{
branch_offset <<= 8;
branch_offset |= *(branch_offset_p++);
/* FALLTHRU */
}
case 2:
{
branch_offset <<= 8;
branch_offset |= *(branch_offset_p++);
break;
}
}
for (uint32_t reg_index = 0;
reg_index < frame_p->regs_number;
reg_index++)
{
ecma_free_value (frame_p->regs_p[reg_index], false);
}
} /* vm_stack_free_frame */
return branch_offset;
} /* vm_decode_branch_offset */
/**
* Get value of specified register variable
* Find a finally up to the end position.
*
* @return ecma-value
* @return true if 'finally' found,
* false otherwise
*/
ecma_value_t
vm_stack_frame_get_reg_value (vm_stack_frame_t *frame_p, /**< frame */
uint32_t reg_index) /**< index of register variable */
bool
vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */
ecma_value_t **vm_stack_top_ref_p, /**< current stack top */
vm_stack_context_type_t finally_type, /**< searching this finally */
uint32_t search_limit) /**< search up-to this byte code */
{
JERRY_ASSERT (reg_index >= VM_REG_FIRST && reg_index < VM_REG_FIRST + frame_p->regs_number);
ecma_value_t *vm_stack_top_p = *vm_stack_top_ref_p;
return frame_p->regs_p[reg_index - VM_REG_FIRST];
} /* vm_stack_frame_get_reg_value */
JERRY_ASSERT (finally_type <= VM_CONTEXT_FINALLY_RETURN);
/**
* Set value of specified register variable
*/
void
vm_stack_frame_set_reg_value (vm_stack_frame_t *frame_p, /**< frame */
uint32_t reg_index, /**< index of register variable */
ecma_value_t value) /**< ecma-value */
{
JERRY_ASSERT (reg_index >= VM_REG_FIRST && reg_index < VM_REG_FIRST + frame_p->regs_number);
frame_p->regs_p[reg_index - VM_REG_FIRST] = value;
} /* vm_stack_frame_set_reg_value */
/**
* Calculate number of value slots in the top-most chunk of the frame
*
* @return number of value slots
*/
static size_t
vm_stack_slots_in_top_chunk (vm_stack_frame_t *frame_p) /**< stack frame */
{
return ((frame_p->top_chunk_p == NULL) ? VM_STACK_FRAME_INLINED_VALUES_NUMBER : VM_STACK_SLOTS_IN_DYNAMIC_CHUNK);
} /* vm_stack_slots_in_top_chunk */
/**
* Longpath for vm_stack_push_value (for case current chunk may be doesn't have free slots)
*/
static void __attr_noinline___
vm_stack_push_value_longpath (vm_stack_frame_t *frame_p) /**< stack frame */
{
JERRY_ASSERT (frame_p->current_slot_index >= JERRY_MIN (VM_STACK_FRAME_INLINED_VALUES_NUMBER,
VM_STACK_SLOTS_IN_DYNAMIC_CHUNK));
const size_t slots_in_top_chunk = vm_stack_slots_in_top_chunk (frame_p);
if (frame_p->current_slot_index == slots_in_top_chunk)
if (finally_type != VM_CONTEXT_FINALLY_JUMP)
{
vm_stack_chunk_header_t *chunk_p;
chunk_p = (vm_stack_chunk_header_t *) mem_heap_alloc_block (VM_STACK_DYNAMIC_CHUNK_SIZE,
MEM_HEAP_ALLOC_SHORT_TERM);
ECMA_SET_POINTER (chunk_p->prev_chunk_p, frame_p->top_chunk_p);
frame_p->top_chunk_p = chunk_p;
frame_p->dynamically_allocated_value_slots_p = (ecma_value_t*) (frame_p->top_chunk_p + 1);
frame_p->current_slot_index = 0;
}
} /* vm_stack_push_value_longpath */
/**
* Push ecma-value to stack
*/
void
vm_stack_push_value (vm_stack_frame_t *frame_p, /**< stack frame */
ecma_value_t value) /**< ecma-value */
{
frame_p->current_slot_index++;
if (frame_p->current_slot_index >= JERRY_MIN (VM_STACK_FRAME_INLINED_VALUES_NUMBER,
VM_STACK_SLOTS_IN_DYNAMIC_CHUNK))
{
vm_stack_push_value_longpath (frame_p);
search_limit = 0xffffffffu;
}
JERRY_ASSERT (frame_p->current_slot_index < vm_stack_slots_in_top_chunk (frame_p));
frame_p->dynamically_allocated_value_slots_p[frame_p->current_slot_index] = value;
} /* vm_stack_push_value */
/**
* Get top value from stack
*/
ecma_value_t __attr_always_inline___
vm_stack_top_value (vm_stack_frame_t *frame_p) /**< stack frame */
{
const size_t slots_in_top_chunk = vm_stack_slots_in_top_chunk (frame_p);
JERRY_ASSERT (frame_p->current_slot_index < slots_in_top_chunk);
return frame_p->dynamically_allocated_value_slots_p[frame_p->current_slot_index];
} /* vm_stack_top_value */
/**
* Longpath for vm_stack_pop (for case a dynamically allocated chunk needs to be deallocated)
*/
static void __attr_noinline___
vm_stack_pop_longpath (vm_stack_frame_t *frame_p) /**< stack frame */
{
JERRY_ASSERT (frame_p->current_slot_index == 0 && frame_p->top_chunk_p != NULL);
vm_stack_chunk_header_t *chunk_to_free_p = frame_p->top_chunk_p;
frame_p->top_chunk_p = ECMA_GET_POINTER (vm_stack_chunk_header_t,
frame_p->top_chunk_p->prev_chunk_p);
if (frame_p->top_chunk_p != NULL)
while (frame_ctx_p->context_depth > 0)
{
frame_p->dynamically_allocated_value_slots_p = (ecma_value_t*) (frame_p->top_chunk_p + 1);
frame_p->current_slot_index = (uint32_t) (VM_STACK_SLOTS_IN_DYNAMIC_CHUNK - 1u);
}
else
{
frame_p->dynamically_allocated_value_slots_p = frame_p->inlined_values;
frame_p->current_slot_index = (uint32_t) (VM_STACK_FRAME_INLINED_VALUES_NUMBER - 1u);
vm_stack_context_type_t context_type;
uint32_t context_end = VM_GET_CONTEXT_END (vm_stack_top_p[-1]);
if (search_limit < context_end)
{
*vm_stack_top_ref_p = vm_stack_top_p;
return false;
}
context_type = VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]);
if (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_CATCH)
{
uint8_t *byte_code_p;
uint32_t branch_offset_length;
uint32_t branch_offset;
if (search_limit == context_end)
{
*vm_stack_top_ref_p = vm_stack_top_p;
return false;
}
byte_code_p = frame_ctx_p->byte_code_start_p + VM_GET_CONTEXT_END (vm_stack_top_p[-1]);
if (context_type == VM_CONTEXT_TRY)
{
JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE);
if (byte_code_p[1] >= CBC_EXT_CATCH
&& byte_code_p[1] <= CBC_EXT_CATCH_3)
{
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]);
branch_offset = vm_decode_branch_offset (byte_code_p + 2,
branch_offset_length);
if (finally_type == VM_CONTEXT_FINALLY_THROW)
{
branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p);
vm_stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_CATCH, branch_offset);
byte_code_p += 2 + branch_offset_length;
frame_ctx_p->byte_code_p = byte_code_p;
*vm_stack_top_ref_p = vm_stack_top_p;
return true;
}
byte_code_p += branch_offset;
if (*byte_code_p == CBC_CONTEXT_END)
{
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
continue;
}
}
}
else
{
ecma_deref_object (frame_ctx_p->lex_env_p);
frame_ctx_p->lex_env_p = ecma_get_object_from_value (vm_stack_top_p[-2]);
if (byte_code_p[0] == CBC_CONTEXT_END)
{
VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION;
continue;
}
}
JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE);
JERRY_ASSERT (byte_code_p[1] >= CBC_EXT_FINALLY
&& byte_code_p[1] <= CBC_EXT_FINALLY_3);
branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]);
branch_offset = vm_decode_branch_offset (byte_code_p + 2,
branch_offset_length);
branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p);
vm_stack_top_p[-1] = VM_CREATE_CONTEXT ((uint32_t) finally_type, branch_offset);
byte_code_p += 2 + branch_offset_length;
frame_ctx_p->byte_code_p = byte_code_p;
*vm_stack_top_ref_p = vm_stack_top_p;
return true;
}
vm_stack_top_p = vm_stack_context_abort (frame_ctx_p, vm_stack_top_p);
}
mem_heap_free_block (chunk_to_free_p);
} /* vm_stack_pop_longpath */
/**
* Pop top value from stack and free it
*/
void
vm_stack_pop (vm_stack_frame_t *frame_p) /**< stack frame */
{
JERRY_ASSERT (frame_p->current_slot_index < vm_stack_slots_in_top_chunk (frame_p));
ecma_value_t value = vm_stack_top_value (frame_p);
if (unlikely (frame_p->current_slot_index == 0
&& frame_p->top_chunk_p != NULL))
{
vm_stack_pop_longpath (frame_p);
}
else
{
frame_p->current_slot_index--;
}
ecma_free_value (value, true);
} /* vm_stack_pop */
/**
* Pop multiple top values from stack and free them
*/
void
vm_stack_pop_multiple (vm_stack_frame_t *frame_p, /**< stack frame */
uint32_t number) /**< number of elements to pop */
{
for (uint32_t i = 0; i < number; i++)
{
vm_stack_pop (frame_p);
}
} /* vm_stack_pop_multiple */
*vm_stack_top_ref_p = vm_stack_top_p;
return false;
} /* vm_stack_find_finally */
/**
* @}
+26 -24
View File
@@ -1,4 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +37,7 @@
*/
typedef struct
{
uint16_t prev_chunk_p; /**< previous chunk of same frame */
uint16_t prev_chunk_p; /**< previous chunk of same frame */
} vm_stack_chunk_header_t;
/**
@@ -44,30 +45,31 @@ typedef struct
*/
typedef struct vm_stack_frame_t
{
struct vm_stack_frame_t *prev_frame_p; /**< previous frame */
vm_stack_chunk_header_t *top_chunk_p; /**< the top-most chunk of the frame */
ecma_value_t *dynamically_allocated_value_slots_p; /**< pointer to dynamically allocated value slots
* in the top-most chunk */
uint32_t current_slot_index; /**< index of first free slot in the top chunk */
ecma_value_t inlined_values[VM_STACK_FRAME_INLINED_VALUES_NUMBER]; /**< place for values inlined into stack frame
* (instead of being placed on heap) */
ecma_value_t *regs_p; /**< register variables */
uint32_t regs_number; /**< number of register variables */
struct vm_stack_frame_t *prev_frame_p; /**< previous frame */
uint32_t regs_number; /**< number of register variables */
} vm_stack_frame_t;
extern void vm_stack_init (void);
extern void vm_stack_finalize (void);
extern vm_stack_frame_t *
vm_stack_get_top_frame (void);
extern void
vm_stack_add_frame (vm_stack_frame_t *, ecma_value_t *, uint32_t, uint32_t, uint32_t, ecma_collection_header_t *);
extern void vm_stack_free_frame (vm_stack_frame_t *);
extern ecma_value_t vm_stack_frame_get_reg_value (vm_stack_frame_t *, uint32_t);
extern void vm_stack_frame_set_reg_value (vm_stack_frame_t *, uint32_t, ecma_value_t);
extern void vm_stack_push_value (vm_stack_frame_t *, ecma_value_t);
extern ecma_value_t vm_stack_top_value (vm_stack_frame_t *);
extern void vm_stack_pop (vm_stack_frame_t *);
extern void vm_stack_pop_multiple (vm_stack_frame_t *, uint32_t);
#define VM_CREATE_CONTEXT(type, end_offset) ((ecma_value_t) ((type) | (end_offset) << 4))
#define VM_GET_CONTEXT_TYPE(value) ((vm_stack_context_type_t) ((value) & 0xf))
#define VM_GET_CONTEXT_END(value) ((value) >> 4)
/**
* Context types for the vm stack.
*/
typedef enum
{
VM_CONTEXT_FINALLY_JUMP, /**< finally context with a jump */
VM_CONTEXT_FINALLY_THROW, /**< finally context with a throw */
VM_CONTEXT_FINALLY_RETURN, /**< finally context with a return */
VM_CONTEXT_TRY, /**< try context */
VM_CONTEXT_CATCH, /**< catch context */
VM_CONTEXT_WITH, /**< with context */
VM_CONTEXT_FOR_IN, /**< for-in context */
} vm_stack_context_type_t;
extern ecma_value_t *vm_stack_context_abort (vm_frame_ctx_t *, ecma_value_t *);
extern bool vm_stack_find_finally (vm_frame_ctx_t *, ecma_value_t **,
vm_stack_context_type_t, uint32_t);
/**
* @}
+2368 -612
View File
File diff suppressed because it is too large Load Diff
+185 -13
View File
@@ -1,4 +1,5 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 University of Szeged.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,25 +19,196 @@
#include "ecma-globals.h"
#include "jrt.h"
#include "opcodes.h"
#include "vm-defines.h"
extern void vm_init (const bytecode_data_header_t *, bool);
/** \addtogroup vm Virtual machine
* @{
*
* \addtogroup vm_executor Executor
* @{
*/
#define VM_OC_GET_DATA_SHIFT 24
#define VM_OC_GET_DATA_MASK 0x1f
#define VM_OC_GET_DATA_CREATE_ID(V) \
(((V) & VM_OC_GET_DATA_MASK) << VM_OC_GET_DATA_SHIFT)
#define VM_OC_GET_DATA_GET_ID(O) \
(((O) >> VM_OC_GET_DATA_SHIFT) & VM_OC_GET_DATA_MASK)
/**
* Argument getters that are part of the opcodes.
*/
typedef enum
{
VM_OC_GET_NONE = VM_OC_GET_DATA_CREATE_ID (0), /**< do nothing */
VM_OC_GET_STACK = VM_OC_GET_DATA_CREATE_ID (1), /**< pop one elemnet from the stack */
VM_OC_GET_STACK_STACK = VM_OC_GET_DATA_CREATE_ID (2), /**< pop two elemnets from the stack */
VM_OC_GET_BYTE = VM_OC_GET_DATA_CREATE_ID (3), /**< read a byte */
VM_OC_GET_LITERAL = VM_OC_GET_DATA_CREATE_ID (4), /**< resolve literal */
VM_OC_GET_STACK_LITERAL = VM_OC_GET_DATA_CREATE_ID (5), /**< pop one elemnet from the stack and resolve a literal*/
VM_OC_GET_LITERAL_BYTE = VM_OC_GET_DATA_CREATE_ID (6), /**< pop one elemnet from stack and read a byte */
VM_OC_GET_LITERAL_LITERAL = VM_OC_GET_DATA_CREATE_ID (7), /**< resolve two literals */
VM_OC_GET_THIS_LITERAL = VM_OC_GET_DATA_CREATE_ID (8), /**< get this and resolve a literal */
} vm_oc_get_types;
#define VM_OC_GROUP_MASK 0xff
#define VM_OC_GROUP_GET_INDEX(O) \
((O) & VM_OC_GROUP_MASK)
/**
* Opcodes.
*/
typedef enum
{
VM_OC_NONE, /**< do nothing */
VM_OC_POP, /**< pop from stack */
VM_OC_POP_BLOCK, /**< pop block */
VM_OC_PUSH, /**< push one element */
VM_OC_PUSH_TWO, /**< push two elements onto the stack */
VM_OC_PUSH_THREE, /**< push three elements onto the stack */
VM_OC_PUSH_UNDEFINED, /**< push undefined value */
VM_OC_PUSH_TRUE, /**< push true value */
VM_OC_PUSH_FALSE, /**< push false value */
VM_OC_PUSH_NULL, /**< push null value */
VM_OC_PUSH_THIS, /**< push this */
VM_OC_PUSH_NUMBER, /**< push number */
VM_OC_PUSH_OBJECT, /**< push object */
VM_OC_SET_PROPERTY, /**< set property */
VM_OC_SET_GETTER, /**< set getter */
VM_OC_SET_SETTER, /**< set setter */
VM_OC_PUSH_UNDEFINED_BASE, /**< push undefined base */
VM_OC_PUSH_ARRAY, /**< push array */
VM_OC_PUSH_ELISON, /**< push elison */
VM_OC_APPEND_ARRAY, /**< append array */
VM_OC_IDENT_REFERENCE, /**< ident reference */
VM_OC_PROP_REFERENCE, /**< prop reference */
VM_OC_PROP_GET, /**< prop get */
/* These eight opcodes must be in this order. */
VM_OC_PROP_PRE_INCR, /**< prefix increment of a property */
VM_OC_PRE_INCR, /**< prefix increment */
VM_OC_PROP_PRE_DECR, /**< prop prefix decrement of a property */
VM_OC_PRE_DECR, /**< prefix decrement */
VM_OC_PROP_POST_INCR, /**< prop postfix increment of a property */
VM_OC_POST_INCR, /**< postfix increment */
VM_OC_PROP_POST_DECR, /**< prop postfix decrement of a property */
VM_OC_POST_DECR, /**< postfix decrement */
VM_OC_PROP_DELETE, /**< delete property */
VM_OC_DELETE, /**< delete */
VM_OC_ASSIGN, /**< assign */
VM_OC_ASSIGN_PROP, /**< assign property */
VM_OC_ASSIGN_PROP_THIS, /**< assign prop this */
VM_OC_RET, /**< return */
VM_OC_THROW, /**< throw */
VM_OC_THROW_REFERENCE_ERROR, /**< throw reference error */
/* The PROP forms must get the highest opcodes. */
VM_OC_EVAL, /**< eval */
VM_OC_CALL_N, /**< call n */
VM_OC_CALL, /**< call */
VM_OC_CALL_PROP_N, /**< call property n */
VM_OC_CALL_PROP, /**< call property */
VM_OC_NEW_N, /**< new n */
VM_OC_NEW, /**< new */
VM_OC_JUMP, /**< jump */
VM_OC_BRANCH_IF_STRICT_EQUAL, /**< branch if stric equal */
/* These four opcodes must be in this order. */
VM_OC_BRANCH_IF_TRUE, /**< branch if true */
VM_OC_BRANCH_IF_FALSE, /**< branch if false */
VM_OC_BRANCH_IF_LOGICAL_TRUE, /**< branch if logical true */
VM_OC_BRANCH_IF_LOGICAL_FALSE, /**< branch if logical false */
VM_OC_PLUS, /**< unary plus */
VM_OC_MINUS, /**< unary minus */
VM_OC_NOT, /**< not */
VM_OC_BIT_NOT, /**< bitwise not */
VM_OC_VOID, /**< void */
VM_OC_TYPEOF_IDENT, /**< typeof identifier */
VM_OC_TYPEOF, /**< typeof */
VM_OC_ADD, /**< binary add */
VM_OC_SUB, /**< binary sub */
VM_OC_MUL, /**< mul */
VM_OC_DIV, /**< div */
VM_OC_MOD, /**< mod */
VM_OC_EQUAL, /**< equal */
VM_OC_NOT_EQUAL, /**< not equal */
VM_OC_STRICT_EQUAL, /**< strict equal */
VM_OC_STRICT_NOT_EQUAL, /**< strict not equal */
VM_OC_LESS, /**< less */
VM_OC_GREATER, /**< greater */
VM_OC_LESS_EQUAL, /**< less equal */
VM_OC_GREATER_EQUAL, /**< greater equal */
VM_OC_IN, /**< in */
VM_OC_INSTANCEOF, /**< instanceof */
VM_OC_BIT_OR, /**< bitwise or */
VM_OC_BIT_XOR, /**< bitwise xor */
VM_OC_BIT_AND, /**< bitwise and */
VM_OC_LEFT_SHIFT, /**< left shift */
VM_OC_RIGHT_SHIFT, /**< right shift */
VM_OC_UNS_RIGHT_SHIFT, /**< unsigned right shift */
VM_OC_WITH, /**< with */
VM_OC_FOR_IN_CREATE_CONTEXT, /**< for in create context */
VM_OC_FOR_IN_GET_NEXT, /**< get next */
VM_OC_FOR_IN_HAS_NEXT, /**< has next */
VM_OC_TRY, /**< try */
VM_OC_CATCH, /**< catch */
VM_OC_FINALLY, /**< finally */
VM_OC_CONTEXT_END, /**< context end */
VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */
} vm_oc_types;
#define VM_OC_PUT_DATA_SHIFT 12
#define VM_OC_PUT_DATA_MASK 0xf
#define VM_OC_PUT_DATA_CREATE_FLAG(V) \
(((V) & VM_OC_PUT_DATA_MASK) << VM_OC_PUT_DATA_SHIFT)
/**
* Result writers that are part of the opcodes.
*/
typedef enum
{
VM_OC_PUT_IDENT = VM_OC_PUT_DATA_CREATE_FLAG (0x1),
VM_OC_PUT_REFERENCE = VM_OC_PUT_DATA_CREATE_FLAG (0x2),
VM_OC_PUT_STACK = VM_OC_PUT_DATA_CREATE_FLAG (0x4),
VM_OC_PUT_BLOCK = VM_OC_PUT_DATA_CREATE_FLAG (0x8),
} vm_oc_put_types;
extern void vm_init (ecma_compiled_code_t *, bool);
extern void vm_finalize (void);
extern jerry_completion_code_t vm_run_global (void);
extern ecma_completion_value_t vm_run_eval (const bytecode_data_header_t *, bool);
extern ecma_completion_value_t vm_run_eval (ecma_compiled_code_t *, bool);
extern ecma_completion_value_t vm_loop (vm_frame_ctx_t *, vm_run_scope_t *);
extern ecma_completion_value_t vm_run_from_pos (const bytecode_data_header_t *, vm_instr_counter_t,
ecma_value_t, ecma_object_t *, bool, bool, ecma_collection_header_t *);
extern ecma_completion_value_t vm_loop (vm_frame_ctx_t *);
extern ecma_completion_value_t vm_run (const ecma_compiled_code_t *,
ecma_value_t,
ecma_object_t *,
bool,
ecma_collection_header_t *);
extern vm_instr_t vm_get_instr (const vm_instr_t *, vm_instr_counter_t);
extern uint8_t vm_get_scope_args_num (const bytecode_data_header_t *, vm_instr_counter_t);
extern ecma_completion_value_t vm_run_array_args (const ecma_compiled_code_t *,
ecma_value_t,
ecma_object_t *,
bool,
const ecma_value_t *,
ecma_length_t);
extern bool vm_is_strict_mode (void);
extern bool vm_is_direct_eval_form_call (void);
extern ecma_value_t vm_get_this_binding (void);
extern ecma_object_t *vm_get_lex_env (void);
#endif /* VM_H */
/**
* @}
* @}
*/
#endif /* !VM_H */
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright 2014 Samsung Electronics Co., Ltd.
// Copyright 2014-2016 Samsung Electronics Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,6 +23,6 @@ assert(big == 2147483648); // overflow on 32bit numbers
big++;
assert(big == 2147483649); // overflow on 32bit numbers
assert ((1152921504606846900).toString() === "1152921504606847000")
assert ((1152921504606846976).toString() === "1152921504606847000")
assert (1.797693134862315808e+308 === Infinity);
+3 -3
View File
@@ -1,5 +1,5 @@
// Copyright 2015 Samsung Electronics Co., Ltd.
// Copyright 2015 University of Szeged.
// Copyright 2015-2016 Samsung Electronics Co., Ltd.
// Copyright 2015-2016 University of Szeged.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
try
{
v_0 = /N(?![^6](?:.)|(?!C[^k-o]*|p){0,}|H)|\\xDF\\db{0,}|i\\0?)/;
v_0 = new RegExp("N(?![^6](?:.)|(?!C[^k-o]*|p){0,}|H)|\\\\xDF\\db{0,}|i\\\\0?)");
assert (false);
}
catch (e)
-144
View File
@@ -1,144 +0,0 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
*
* 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 "bytecode-data.h"
#include "mem-allocator.h"
#include "opcodes.h"
#include "parser.h"
#include "test-common.h"
static bool
instrs_equal (const vm_instr_t *instrs1, vm_instr_t *instrs2, uint16_t size)
{
static const uint8_t instr_fields_num[] =
{
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
1,
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg1, arg1_type) \
2,
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type) \
3,
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg1, arg1_type, arg2, arg2_type, arg3, arg3_type) \
4,
#include "vm-opcodes.inc.h"
};
uint16_t i;
for (i = 0; i < size; i++)
{
if (memcmp (&instrs1[i], &instrs2[i], instr_fields_num[instrs1[i].op_idx] * sizeof (vm_idx_t)) != 0)
{
return false;
}
}
return true;
}
#define VM_OP_0(opcode_name, opcode_name_uppercase) \
static vm_instr_t __attr_unused___ getop_##opcode_name (void) \
{ \
vm_instr_t instr; \
instr.op_idx = VM_OP_##opcode_name_uppercase; \
instr.data.raw_args[0] = VM_IDX_EMPTY; \
instr.data.raw_args[1] = VM_IDX_EMPTY; \
instr.data.raw_args[2] = VM_IDX_EMPTY; \
return instr; \
}
#define VM_OP_1(opcode_name, opcode_name_uppercase, arg_1, arg1_type) \
static vm_instr_t __attr_unused___ getop_##opcode_name (vm_idx_t arg1_v) \
{ \
vm_instr_t instr; \
instr.op_idx = VM_OP_##opcode_name_uppercase; \
instr.data.raw_args[0] = arg1_v; \
instr.data.raw_args[1] = VM_IDX_EMPTY; \
instr.data.raw_args[2] = VM_IDX_EMPTY; \
return instr; \
}
#define VM_OP_2(opcode_name, opcode_name_uppercase, arg_1, arg1_type, arg_2, arg2_type) \
static vm_instr_t __attr_unused___ getop_##opcode_name (vm_idx_t arg1_v, vm_idx_t arg2_v) \
{ \
vm_instr_t instr; \
instr.op_idx = VM_OP_##opcode_name_uppercase; \
instr.data.raw_args[0] = arg1_v; \
instr.data.raw_args[1] = arg2_v; \
instr.data.raw_args[2] = VM_IDX_EMPTY; \
return instr; \
}
#define VM_OP_3(opcode_name, opcode_name_uppercase, arg_1, arg1_type, arg_2, arg2_type, arg3_name, arg3_type) \
static vm_instr_t __attr_unused___ getop_##opcode_name (vm_idx_t arg1_v, vm_idx_t arg2_v, vm_idx_t arg3_v) \
{ \
vm_instr_t instr; \
instr.op_idx = VM_OP_##opcode_name_uppercase; \
instr.data.raw_args[0] = arg1_v; \
instr.data.raw_args[1] = arg2_v; \
instr.data.raw_args[2] = arg3_v; \
return instr; \
}
#include "vm-opcodes.inc.h"
/**
* Unit test's main function.
*/
int
main (int __attr_unused___ argc,
char __attr_unused___ **argv)
{
TEST_INIT ();
const bytecode_data_header_t *bytecode_data_p;
jsp_status_t parse_status;
mem_init ();
// #1
char program1[] = "a=1;var a;";
lit_init ();
parser_set_show_instrs (true);
parse_status = parser_parse_script ((jerry_api_char_t *) program1, strlen (program1), &bytecode_data_p);
JERRY_ASSERT (parse_status == JSP_STATUS_OK && bytecode_data_p != NULL);
vm_instr_t instrs[] =
{
getop_reg_var_decl (1u, 0u, 0u),
getop_assignment (0, 1, 1), // a = 1 (SMALLINT);
getop_ret () // return;
};
JERRY_ASSERT (instrs_equal (bytecode_data_p->instrs_p, instrs, 3));
lit_finalize ();
bc_finalize ();
// #2
char program2[] = "var var;";
lit_init ();
parser_set_show_instrs (true);
parse_status = parser_parse_script ((jerry_api_char_t *) program2, strlen (program2), &bytecode_data_p);
JERRY_ASSERT (parse_status == JSP_STATUS_SYNTAX_ERROR && bytecode_data_p == NULL);
lit_finalize ();
bc_finalize ();
mem_finalize (false);
return 0;
} /* main */
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright 2014-2015 Samsung Electronics Co., Ltd.
# Copyright 2014-2016 Samsung Electronics Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
TIMEOUT=${TIMEOUT:=30}
TIMEOUT=${TIMEOUT:=5}
START_DIR=`pwd`