diff --git a/jerry-core/config.h b/jerry-core/config.h index e8cee4c0b..5fd33efa2 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -129,11 +129,6 @@ && CONFIG_ECMA_CHAR_ENCODING != CONFIG_ECMA_CHAR_UTF16 */ #endif /* CONFIG_ECMA_CHAR_ENCODING */ -/** - * Number of ecma-values inlined into stack frame - */ -#define CONFIG_ECMA_STACK_FRAME_INLINED_VALUES_NUMBER (16) - /** * Disable ECMA lookup cache */ @@ -162,6 +157,11 @@ #define CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN #endif /* CONFIG_ECMA_COMPACT_PROFILE */ +/** + * Number of ecma-values inlined into VM stack frame + */ +#define CONFIG_VM_STACK_FRAME_INLINED_VALUES_NUMBER (16) + /** * Run GC after execution of each opcode */ diff --git a/jerry-core/ecma/base/ecma-gc.cpp b/jerry-core/ecma/base/ecma-gc.cpp index a7b71f377..71bc56d43 100644 --- a/jerry-core/ecma/base/ecma-gc.cpp +++ b/jerry-core/ecma/base/ecma-gc.cpp @@ -29,14 +29,19 @@ #include "ecma-gc.h" #include "ecma-helpers.h" #include "ecma-lcache.h" -#include "ecma-stack.h" #include "jrt.h" #include "jrt-libc-includes.h" #include "jrt-bit-fields.h" +#include "vm-stack.h" #define JERRY_INTERNAL #include "jerry-internal.h" +/** + * TODO: + * Extract GC to a separate component + */ + /** * An object's GC color * @@ -427,13 +432,13 @@ 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 (ecma_stack_frame_t *frame_iter_p = ecma_stack_get_top_frame (); + 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 (int32_t reg_index = 0; reg_index < frame_iter_p->regs_number; reg_index++) { - ecma_value_t reg_value = ecma_stack_frame_get_reg_value (frame_iter_p, reg_index); + ecma_value_t reg_value = vm_stack_frame_get_reg_value (frame_iter_p, reg_index); if (ecma_is_value_object (reg_value)) { diff --git a/jerry-core/ecma/base/ecma-init-finalize.cpp b/jerry-core/ecma/base/ecma-init-finalize.cpp index 835dac6b6..8cdb23cf6 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.cpp +++ b/jerry-core/ecma/base/ecma-init-finalize.cpp @@ -19,7 +19,6 @@ #include "ecma-init-finalize.h" #include "ecma-lcache.h" #include "ecma-lex-env.h" -#include "ecma-stack.h" #include "mem-allocator.h" /** \addtogroup ecma ECMA @@ -37,7 +36,6 @@ ecma_init (void) { ecma_init_builtins (); ecma_lcache_init (); - ecma_stack_init (); ecma_init_environment (); mem_register_a_try_give_memory_back_callback (ecma_try_to_give_back_some_memory); @@ -52,7 +50,6 @@ ecma_finalize (void) mem_unregister_a_try_give_memory_back_callback (ecma_try_to_give_back_some_memory); ecma_finalize_environment (); - ecma_stack_finalize (); ecma_finalize_builtins (); ecma_lcache_invalidate_all (); ecma_gc_run (); diff --git a/jerry-core/ecma/base/ecma-stack.cpp b/jerry-core/ecma/base/ecma-stack.cpp deleted file mode 100644 index 006698617..000000000 --- a/jerry-core/ecma/base/ecma-stack.cpp +++ /dev/null @@ -1,283 +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 "ecma-helpers.h" -#include "ecma-stack.h" - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup ecmastack ecma-stack - * @{ - */ - -/** - * Size of a ecma-stack frame's dynamic chunk - */ -#define ECMA_STACK_DYNAMIC_CHUNK_SIZE (mem_heap_recommend_allocation_size (sizeof (ecma_stack_chunk_header_t) + \ - sizeof (ecma_value_t))) - -/** - * Number of value slots in a ecma-stack frame's dynamic chunk - */ -#define ECMA_STACK_SLOTS_IN_DYNAMIC_CHUNK ((ECMA_STACK_DYNAMIC_CHUNK_SIZE - sizeof (ecma_stack_chunk_header_t)) / \ - sizeof (ecma_value_t)) - -/** - * The top-most ecma-stack frame - */ -ecma_stack_frame_t* ecma_stack_top_frame_p; - -/** - * Initialize ecma-stack - */ -void -ecma_stack_init (void) -{ - ecma_stack_top_frame_p = NULL; -} /* ecma_stack_init */ - -/** - * Finalize ecma-stack - */ -void -ecma_stack_finalize () -{ - JERRY_ASSERT (ecma_stack_top_frame_p == NULL); -} /* ecma_stack_finalize */ - -/** - * Get ecma-stack's top frame - * - * @return pointer to the top frame descriptor - */ -ecma_stack_frame_t* -ecma_stack_get_top_frame (void) -{ - return ecma_stack_top_frame_p; -} /* ecma_stack_get_top_frame */ - -/** - * Add the frame to ecma-stack - */ -void -ecma_stack_add_frame (ecma_stack_frame_t *frame_p, /**< frame to initialize */ - ecma_value_t *regs_p, /**< array of register variables' values */ - int32_t regs_num) /**< number of register variables */ -{ - frame_p->prev_frame_p = ecma_stack_top_frame_p; - ecma_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; - - for (int32_t i = 0; i < regs_num; i++) - { - regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); - } -} /* ecma_stack_add_frame */ - -/** - * Free the ecma-stack frame - * - * Note: - * the frame should be the top-most frame - */ -void -ecma_stack_free_frame (ecma_stack_frame_t *frame_p) /**< frame to initialize */ -{ - /* the frame should be the top-most frame */ - JERRY_ASSERT (ecma_stack_top_frame_p == frame_p); - - ecma_stack_top_frame_p = frame_p->prev_frame_p; - - while (frame_p->top_chunk_p != NULL) - { - ecma_stack_pop (frame_p); - } - - for (int32_t reg_index = 0; - reg_index < frame_p->regs_number; - reg_index++) - { - ecma_free_value (frame_p->regs_p[reg_index], false); - } -} /* ecma_stack_free_frame */ - -/** - * Get value of specified register variable - * - * @return ecma-value - */ -ecma_value_t -ecma_stack_frame_get_reg_value (ecma_stack_frame_t *frame_p, /**< frame */ - int32_t reg_index) /**< index of register variable */ -{ - JERRY_ASSERT (reg_index >= 0 && reg_index < frame_p->regs_number); - - return frame_p->regs_p[reg_index]; -} /* ecma_stack_frame_get_reg_value */ - -/** - * Set value of specified register variable - */ -void -ecma_stack_frame_set_reg_value (ecma_stack_frame_t *frame_p, /**< frame */ - int32_t reg_index, /**< index of register variable */ - ecma_value_t value) /**< ecma-value */ -{ - JERRY_ASSERT (reg_index >= 0 && reg_index < frame_p->regs_number); - - frame_p->regs_p[reg_index] = value; -} /* ecma_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 -ecma_stack_slots_in_top_chunk (ecma_stack_frame_t *frame_p) /**< ecma-stack frame */ -{ - return ((frame_p->top_chunk_p == NULL) ? ECMA_STACK_FRAME_INLINED_VALUES_NUMBER : ECMA_STACK_SLOTS_IN_DYNAMIC_CHUNK); -} /* ecma_stack_slots_in_top_chunk */ - -/** - * Longpath for ecma_stack_push_value (for case current chunk may be doesn't have free slots) - */ -static void __attr_noinline___ -ecma_stack_push_value_longpath (ecma_stack_frame_t *frame_p) /**< ecma-stack frame */ -{ - JERRY_ASSERT (frame_p->current_slot_index >= JERRY_MIN (ECMA_STACK_FRAME_INLINED_VALUES_NUMBER, - ECMA_STACK_SLOTS_IN_DYNAMIC_CHUNK)); - - const size_t slots_in_top_chunk = ecma_stack_slots_in_top_chunk (frame_p); - - if (frame_p->current_slot_index == slots_in_top_chunk) - { - ecma_stack_chunk_header_t *chunk_p; - chunk_p = (ecma_stack_chunk_header_t *) mem_heap_alloc_block (ECMA_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; - } -} /* ecma_stack_push_value_longpath */ - -/** - * Push ecma-value to ecma-stack - */ -void -ecma_stack_push_value (ecma_stack_frame_t *frame_p, /**< ecma-stack frame */ - ecma_value_t value) /**< ecma-value */ -{ - frame_p->current_slot_index++; - - if (frame_p->current_slot_index >= JERRY_MIN (ECMA_STACK_FRAME_INLINED_VALUES_NUMBER, - ECMA_STACK_SLOTS_IN_DYNAMIC_CHUNK)) - { - ecma_stack_push_value_longpath (frame_p); - } - - JERRY_ASSERT (frame_p->current_slot_index < ecma_stack_slots_in_top_chunk (frame_p)); - - frame_p->dynamically_allocated_value_slots_p[frame_p->current_slot_index] = value; -} /* ecma_stack_push_value */ - -/** - * Get top value from ecma-stack - */ -ecma_value_t __attr_always_inline___ -ecma_stack_top_value (ecma_stack_frame_t *frame_p) /**< ecma-stack frame */ -{ - const size_t slots_in_top_chunk = ecma_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]; -} /* ecma_stack_top_value */ - -/** - * Longpath for ecma_stack_pop (for case a dynamically allocated chunk needs to be deallocated) - */ -static void __attr_noinline___ -ecma_stack_pop_longpath (ecma_stack_frame_t *frame_p) /**< ecma-stack frame */ -{ - JERRY_ASSERT (frame_p->current_slot_index == 0 && frame_p->top_chunk_p != NULL); - - ecma_stack_chunk_header_t *chunk_to_free_p = frame_p->top_chunk_p; - frame_p->top_chunk_p = ECMA_GET_POINTER (ecma_stack_chunk_header_t, - frame_p->top_chunk_p->prev_chunk_p); - - if (frame_p->top_chunk_p != NULL) - { - frame_p->dynamically_allocated_value_slots_p = (ecma_value_t*) (frame_p->top_chunk_p + 1); - frame_p->current_slot_index = (uint32_t) (ECMA_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) (ECMA_STACK_FRAME_INLINED_VALUES_NUMBER - 1u); - } - - mem_heap_free_block (chunk_to_free_p); -} /* ecma_stack_pop_longpath */ - -/** - * Pop top value from ecma-stack and free it - */ -void -ecma_stack_pop (ecma_stack_frame_t *frame_p) /**< ecma-stack frame */ -{ - JERRY_ASSERT (frame_p->current_slot_index < ecma_stack_slots_in_top_chunk (frame_p)); - - ecma_value_t value = ecma_stack_top_value (frame_p); - - if (unlikely (frame_p->current_slot_index == 0 - && frame_p->top_chunk_p != NULL)) - { - ecma_stack_pop_longpath (frame_p); - } - else - { - frame_p->current_slot_index--; - } - - ecma_free_value (value, true); -} /* ecma_stack_pop */ - -/** - * Pop multiple top values from ecma-stack and free them - */ -void -ecma_stack_pop_multiple (ecma_stack_frame_t *frame_p, /**< ecma-stack frame */ - uint32_t number) /**< number of elements to pop */ -{ - for (uint32_t i = 0; i < number; i++) - { - ecma_stack_pop (frame_p); - } -} /* ecma_stack_pop_multiple */ - -/** - * @} - * @} - */ diff --git a/jerry-core/ecma/base/ecma-stack.h b/jerry-core/ecma/base/ecma-stack.h deleted file mode 100644 index 2f8c2da12..000000000 --- a/jerry-core/ecma/base/ecma-stack.h +++ /dev/null @@ -1,80 +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 ECMA_STACK_H -#define ECMA_STACK_H - -#include "config.h" -#include "ecma-globals.h" - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup ecmastack ECMA stack - * @{ - */ - -/** - * Number of ecma-values inlined into stack frame - */ -#define ECMA_STACK_FRAME_INLINED_VALUES_NUMBER CONFIG_ECMA_STACK_FRAME_INLINED_VALUES_NUMBER - -/** - * Header of a ECMA stack frame's chunk - */ -typedef struct -{ - uint16_t prev_chunk_p; /**< previous chunk of same frame */ -} ecma_stack_chunk_header_t; - -/** - * ECMA stack frame - */ -typedef struct ecma_stack_frame_t -{ - struct ecma_stack_frame_t *prev_frame_p; /**< previous frame */ - ecma_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[ECMA_STACK_FRAME_INLINED_VALUES_NUMBER]; /**< place for values inlined in stack frame - * (instead of being dynamically allocated - * on the heap) */ - ecma_value_t *regs_p; /**< register variables */ - int32_t regs_number; /**< number of register variables */ -} ecma_stack_frame_t; - -extern void ecma_stack_init (void); -extern void ecma_stack_finalize (void); -extern ecma_stack_frame_t* -ecma_stack_get_top_frame (void); -extern void -ecma_stack_add_frame (ecma_stack_frame_t *frame_p, - ecma_value_t *regs_p, - int32_t regs_num); -extern void ecma_stack_free_frame (ecma_stack_frame_t *frame_p); -extern ecma_value_t ecma_stack_frame_get_reg_value (ecma_stack_frame_t *frame_p, int32_t reg_index); -extern void ecma_stack_frame_set_reg_value (ecma_stack_frame_t *frame_p, int32_t reg_index, ecma_value_t value); -extern void ecma_stack_push_value (ecma_stack_frame_t *frame_p, ecma_value_t value); -extern ecma_value_t ecma_stack_top_value (ecma_stack_frame_t *frame_p); -extern void ecma_stack_pop (ecma_stack_frame_t *frame_p); -extern void ecma_stack_pop_multiple (ecma_stack_frame_t *frame_p, uint32_t number); - -/** - * @} - * @} - */ - -#endif /* !ECMA_STACK_H */ diff --git a/jerry-core/vm/opcodes-helpers-variables.cpp b/jerry-core/vm/opcodes-helpers-variables.cpp index a9e108087..46fc698ff 100644 --- a/jerry-core/vm/opcodes-helpers-variables.cpp +++ b/jerry-core/vm/opcodes-helpers-variables.cpp @@ -81,8 +81,8 @@ get_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ if (is_reg_variable (frame_ctx_p, var_idx)) { - ecma_value_t reg_value = ecma_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, - var_idx - frame_ctx_p->min_reg_num); + ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, + var_idx - frame_ctx_p->min_reg_num); JERRY_ASSERT (!ecma_is_value_empty (reg_value)); @@ -135,8 +135,8 @@ set_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ { ret_value = ecma_make_empty_completion_value (); - ecma_value_t reg_value = ecma_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, - var_idx - frame_ctx_p->min_reg_num); + ecma_value_t reg_value = vm_stack_frame_get_reg_value (&frame_ctx_p->stack_frame, + var_idx - frame_ctx_p->min_reg_num); if (ecma_is_value_number (reg_value) && ecma_is_value_number (value)) @@ -150,8 +150,8 @@ set_variable_value (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ ecma_free_value (reg_value, false); } - ecma_stack_frame_set_reg_value (&frame_ctx_p->stack_frame, - var_idx - frame_ctx_p->min_reg_num, + vm_stack_frame_set_reg_value (&frame_ctx_p->stack_frame, + var_idx - frame_ctx_p->min_reg_num, ecma_copy_value (value, false)); } } diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 5cf30e266..bdb1a05d5 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -17,8 +17,8 @@ #define OPCODES_H #include "ecma-globals.h" -#include "ecma-stack.h" #include "jrt.h" +#include "vm-stack.h" /* Maximum opcodes number in bytecode. */ #define MAX_OPCODES (256*256 - 1) @@ -138,7 +138,7 @@ typedef struct idx_t min_reg_num; /**< minimum idx used for register identification */ idx_t max_reg_num; /**< maximum idx used for register identification */ ecma_number_t* tmp_num_p; /**< an allocated number (to reduce temporary allocations) */ - ecma_stack_frame_t stack_frame; /**< ecma-stack frame associated with the context */ + vm_stack_frame_t stack_frame; /**< stack frame associated with the context */ #ifdef MEM_STATS size_t context_peak_allocated_heap_bytes; diff --git a/jerry-core/vm/vm-stack.cpp b/jerry-core/vm/vm-stack.cpp new file mode 100644 index 000000000..58e49eed5 --- /dev/null +++ b/jerry-core/vm/vm-stack.cpp @@ -0,0 +1,284 @@ +/* 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 "ecma-globals.h" +#include "ecma-helpers.h" +#include "vm-stack.h" + +/** \addtogroup vm Virtual machine + * @{ + * + * \addtogroup stack VM stack + * @{ + */ + +/** + * 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 + * + * @return pointer to the top frame descriptor + */ +vm_stack_frame_t* +vm_stack_get_top_frame (void) +{ + 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 */ + int32_t regs_num) /**< number of register variables */ +{ + 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; + + for (int32_t i = 0; i < regs_num; i++) + { + regs_p[i] = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); + } +} /* vm_stack_add_frame */ + +/** + * Free the stack frame + * + * Note: + * the frame should be the top-most frame + */ +void +vm_stack_free_frame (vm_stack_frame_t *frame_p) /**< frame to initialize */ +{ + /* the frame should be the top-most frame */ + JERRY_ASSERT (vm_stack_top_frame_p == frame_p); + + vm_stack_top_frame_p = frame_p->prev_frame_p; + + while (frame_p->top_chunk_p != NULL) + { + vm_stack_pop (frame_p); + } + + for (int32_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 */ + +/** + * Get value of specified register variable + * + * @return ecma-value + */ +ecma_value_t +vm_stack_frame_get_reg_value (vm_stack_frame_t *frame_p, /**< frame */ + int32_t reg_index) /**< index of register variable */ +{ + JERRY_ASSERT (reg_index >= 0 && reg_index < frame_p->regs_number); + + return frame_p->regs_p[reg_index]; +} /* vm_stack_frame_get_reg_value */ + +/** + * Set value of specified register variable + */ +void +vm_stack_frame_set_reg_value (vm_stack_frame_t *frame_p, /**< frame */ + int32_t reg_index, /**< index of register variable */ + ecma_value_t value) /**< ecma-value */ +{ + JERRY_ASSERT (reg_index >= 0 && reg_index < frame_p->regs_number); + + frame_p->regs_p[reg_index] = 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) + { + 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); + } + + 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) + { + 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); + } + + 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 */ + +/** + * @} + * @} + */ diff --git a/jerry-core/vm/vm-stack.h b/jerry-core/vm/vm-stack.h new file mode 100644 index 000000000..8484af333 --- /dev/null +++ b/jerry-core/vm/vm-stack.h @@ -0,0 +1,79 @@ +/* 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 VM_STACK_H +#define VM_STACK_H + +#include "config.h" +#include "ecma-globals.h" + +/** \addtogroup vm Virtual machine + * @{ + * + * \addtogroup stack VM stack + * @{ + */ + +/** + * Number of ecma-values inlined into stack frame + */ +#define VM_STACK_FRAME_INLINED_VALUES_NUMBER CONFIG_VM_STACK_FRAME_INLINED_VALUES_NUMBER + +/** + * Header of a ECMA stack frame's chunk + */ +typedef struct +{ + uint16_t prev_chunk_p; /**< previous chunk of same frame */ +} vm_stack_chunk_header_t; + +/** + * ECMA stack frame + */ +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 */ + int32_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 *frame_p, + ecma_value_t *regs_p, + int32_t regs_num); +extern void vm_stack_free_frame (vm_stack_frame_t *frame_p); +extern ecma_value_t vm_stack_frame_get_reg_value (vm_stack_frame_t *frame_p, int32_t reg_index); +extern void vm_stack_frame_set_reg_value (vm_stack_frame_t *frame_p, int32_t reg_index, ecma_value_t value); +extern void vm_stack_push_value (vm_stack_frame_t *frame_p, ecma_value_t value); +extern ecma_value_t vm_stack_top_value (vm_stack_frame_t *frame_p); +extern void vm_stack_pop (vm_stack_frame_t *frame_p); +extern void vm_stack_pop_multiple (vm_stack_frame_t *frame_p, uint32_t number); + +/** + * @} + * @} + */ + +#endif /* !VM_STACK_H */ diff --git a/jerry-core/vm/vm.cpp b/jerry-core/vm/vm.cpp index e5dd28024..e35b7829a 100644 --- a/jerry-core/vm/vm.cpp +++ b/jerry-core/vm/vm.cpp @@ -19,11 +19,11 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-lex-env.h" -#include "ecma-stack.h" #include "jrt.h" -#include "vm.h" #include "jrt-libc-includes.h" #include "mem-allocator.h" +#include "vm.h" +#include "vm-stack.h" /** * Top (current) interpreter context @@ -348,6 +348,8 @@ vm_init (const opcode_t *program_p, /**< pointer to byte-code program */ JERRY_ASSERT (__program == NULL); + vm_stack_init (); + __program = program_p; } /* vm_init */ @@ -357,6 +359,8 @@ vm_init (const opcode_t *program_p, /**< pointer to byte-code program */ void vm_finalize (void) { + vm_stack_finalize (); + __program = NULL; } /* vm_finalize */ @@ -544,7 +548,7 @@ vm_run_from_pos (const opcode_t *opcodes_p, /**< byte-code array */ frame_ctx.min_reg_num = min_reg_num; frame_ctx.max_reg_num = max_reg_num; frame_ctx.tmp_num_p = ecma_alloc_number (); - ecma_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num); + vm_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num); vm_frame_ctx_t *prev_context_p = vm_top_context_p; vm_top_context_p = &frame_ctx; @@ -560,7 +564,7 @@ vm_run_from_pos (const opcode_t *opcodes_p, /**< byte-code array */ vm_top_context_p = prev_context_p; - ecma_stack_free_frame (&frame_ctx.stack_frame); + vm_stack_free_frame (&frame_ctx.stack_frame); ecma_dealloc_number (frame_ctx.tmp_num_p);