1/* Copyright JS Foundation and other contributors, http://js.foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecma-alloc.h" 17#include "ecma-gc.h" 18#include "ecma-helpers.h" 19#include "vm-defines.h" 20#include "vm-stack.h" 21#include "ecma-iterator-object.h" 22 23/** \addtogroup vm Virtual machine 24 * @{ 25 * 26 * \addtogroup stack VM stack 27 * @{ 28 */ 29 30JERRY_STATIC_ASSERT (PARSER_WITH_CONTEXT_STACK_ALLOCATION == PARSER_BLOCK_CONTEXT_STACK_ALLOCATION, 31 parser_with_context_stack_allocation_must_be_equal_to_parser_block_context_stack_allocation); 32 33/** 34 * Abort (finalize) the current stack context, and remove it. 35 * 36 * @return new stack top 37 */ 38ecma_value_t * 39vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ 40 ecma_value_t *vm_stack_top_p) /**< current stack top */ 41{ 42 ecma_value_t context_info = vm_stack_top_p[-1]; 43 44 if (context_info & VM_CONTEXT_HAS_LEX_ENV) 45 { 46 ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; 47 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); 48 frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); 49 ecma_deref_object (lex_env_p); 50 } 51 52 switch (VM_GET_CONTEXT_TYPE (context_info)) 53 { 54 case VM_CONTEXT_FINALLY_THROW: 55 case VM_CONTEXT_FINALLY_RETURN: 56 { 57 ecma_free_value (vm_stack_top_p[-2]); 58 /* FALLTHRU */ 59 } 60 case VM_CONTEXT_FINALLY_JUMP: 61 case VM_CONTEXT_TRY: 62 case VM_CONTEXT_CATCH: 63 { 64 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); 65 vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; 66 break; 67 } 68#if ENABLED (JERRY_ES2015) 69 case VM_CONTEXT_BLOCK: 70#endif /* ENABLED (JERRY_ES2015) */ 71 case VM_CONTEXT_WITH: 72 { 73 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_WITH_CONTEXT_STACK_ALLOCATION); 74 vm_stack_top_p -= PARSER_WITH_CONTEXT_STACK_ALLOCATION; 75 break; 76 } 77#if ENABLED (JERRY_ES2015) 78 case VM_CONTEXT_FOR_OF: 79 { 80 ecma_value_t iterator = vm_stack_top_p[-3]; 81 82 if (context_info & VM_CONTEXT_CLOSE_ITERATOR) 83 { 84 ecma_op_iterator_close (iterator); 85 } 86 ecma_free_value (iterator); 87 88 ecma_free_value (vm_stack_top_p[-2]); 89 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); 90 vm_stack_top_p -= PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION; 91 break; 92 } 93#endif /* ENABLED (JERRY_ES2015) */ 94 default: 95 { 96 JERRY_ASSERT (VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]) == VM_CONTEXT_FOR_IN); 97 98 ecma_collection_t *collection_p; 99 collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, vm_stack_top_p[-2]); 100 101 ecma_value_t *buffer_p = collection_p->buffer_p; 102 103 for (uint32_t index = vm_stack_top_p[-3]; index < collection_p->item_count; index++) 104 { 105 ecma_free_value (buffer_p[index]); 106 } 107 108 ecma_collection_destroy (collection_p); 109 110 ecma_free_value (vm_stack_top_p[-4]); 111 112 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); 113 vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; 114 break; 115 } 116 } 117 118 return vm_stack_top_p; 119} /* vm_stack_context_abort */ 120 121/** 122 * Decode branch offset. 123 * 124 * @return branch offset 125 */ 126static uint32_t 127vm_decode_branch_offset (const uint8_t *branch_offset_p, /**< start offset of byte code */ 128 uint32_t length) /**< length of the branch */ 129{ 130 uint32_t branch_offset = *branch_offset_p; 131 132 JERRY_ASSERT (length >= 1 && length <= 3); 133 134 switch (length) 135 { 136 case 3: 137 { 138 branch_offset <<= 8; 139 branch_offset |= *(++branch_offset_p); 140 /* FALLTHRU */ 141 } 142 case 2: 143 { 144 branch_offset <<= 8; 145 branch_offset |= *(++branch_offset_p); 146 break; 147 } 148 } 149 150 return branch_offset; 151} /* vm_decode_branch_offset */ 152 153/** 154 * Find a finally up to the end position. 155 * 156 * @return true - if 'finally' found, 157 * false - otherwise 158 */ 159bool 160vm_stack_find_finally (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ 161 ecma_value_t **vm_stack_top_ref_p, /**< current stack top */ 162 vm_stack_context_type_t finally_type, /**< searching this finally */ 163 uint32_t search_limit) /**< search up-to this byte code */ 164{ 165 ecma_value_t *vm_stack_top_p = *vm_stack_top_ref_p; 166 167 JERRY_ASSERT (finally_type <= VM_CONTEXT_FINALLY_RETURN); 168 169 if (finally_type != VM_CONTEXT_FINALLY_JUMP) 170 { 171 search_limit = 0xffffffffu; 172 } 173 174 while (frame_ctx_p->context_depth > 0) 175 { 176 vm_stack_context_type_t context_type; 177 uint32_t context_end = VM_GET_CONTEXT_END (vm_stack_top_p[-1]); 178 179 if (search_limit < context_end) 180 { 181 *vm_stack_top_ref_p = vm_stack_top_p; 182 return false; 183 } 184 185 context_type = VM_GET_CONTEXT_TYPE (vm_stack_top_p[-1]); 186 if (context_type == VM_CONTEXT_TRY || context_type == VM_CONTEXT_CATCH) 187 { 188 const uint8_t *byte_code_p; 189 uint32_t branch_offset_length; 190 uint32_t branch_offset; 191 192 if (search_limit == context_end) 193 { 194 *vm_stack_top_ref_p = vm_stack_top_p; 195 return false; 196 } 197 198#if ENABLED (JERRY_ES2015) 199 if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) 200 { 201 ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; 202 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); 203 frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); 204 ecma_deref_object (lex_env_p); 205 } 206#endif /* ENABLED (JERRY_ES2015) */ 207 208 byte_code_p = frame_ctx_p->byte_code_start_p + context_end; 209 210 if (context_type == VM_CONTEXT_TRY) 211 { 212 JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE); 213 214 if (byte_code_p[1] >= CBC_EXT_CATCH 215 && byte_code_p[1] <= CBC_EXT_CATCH_3) 216 { 217 branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]); 218 branch_offset = vm_decode_branch_offset (byte_code_p + 2, 219 branch_offset_length); 220 221 if (finally_type == VM_CONTEXT_FINALLY_THROW) 222 { 223 branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p); 224 225 vm_stack_top_p[-1] = VM_CREATE_CONTEXT (VM_CONTEXT_CATCH, branch_offset); 226 227 byte_code_p += 2 + branch_offset_length; 228 frame_ctx_p->byte_code_p = byte_code_p; 229 230 *vm_stack_top_ref_p = vm_stack_top_p; 231 return true; 232 } 233 234 byte_code_p += branch_offset; 235 236 if (*byte_code_p == CBC_CONTEXT_END) 237 { 238 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); 239 vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; 240 continue; 241 } 242 } 243 } 244 else 245 { 246#if !ENABLED (JERRY_ES2015) 247 if (vm_stack_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) 248 { 249 ecma_object_t *lex_env_p = frame_ctx_p->lex_env_p; 250 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); 251 frame_ctx_p->lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); 252 ecma_deref_object (lex_env_p); 253 } 254#endif /* !ENABLED (JERRY_ES2015) */ 255 256 if (byte_code_p[0] == CBC_CONTEXT_END) 257 { 258 VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); 259 vm_stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; 260 continue; 261 } 262 } 263 264 JERRY_ASSERT (byte_code_p[0] == CBC_EXT_OPCODE); 265 JERRY_ASSERT (byte_code_p[1] >= CBC_EXT_FINALLY 266 && byte_code_p[1] <= CBC_EXT_FINALLY_3); 267 268 branch_offset_length = CBC_BRANCH_OFFSET_LENGTH (byte_code_p[1]); 269 branch_offset = vm_decode_branch_offset (byte_code_p + 2, 270 branch_offset_length); 271 272 branch_offset += (uint32_t) (byte_code_p - frame_ctx_p->byte_code_start_p); 273 274 vm_stack_top_p[-1] = VM_CREATE_CONTEXT ((uint32_t) finally_type, branch_offset); 275 276 byte_code_p += 2 + branch_offset_length; 277 frame_ctx_p->byte_code_p = byte_code_p; 278 279 *vm_stack_top_ref_p = vm_stack_top_p; 280 return true; 281 } 282 283 vm_stack_top_p = vm_stack_context_abort (frame_ctx_p, vm_stack_top_p); 284 } 285 286 *vm_stack_top_ref_p = vm_stack_top_p; 287 return false; 288} /* vm_stack_find_finally */ 289 290#if ENABLED (JERRY_ES2015) 291 292/** 293 * Get the offsets of ecma values from the specified item of a context. 294 * 295 * @return array of offsets, last item represents the size of the context item 296 */ 297uint32_t 298vm_get_context_value_offsets (ecma_value_t *context_item_p) /**< any item of a context */ 299{ 300 switch (VM_GET_CONTEXT_TYPE (context_item_p[-1])) 301 { 302 case VM_CONTEXT_FINALLY_THROW: 303 case VM_CONTEXT_FINALLY_RETURN: 304 { 305 return (2 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_TRY_CONTEXT_STACK_ALLOCATION; 306 } 307 case VM_CONTEXT_FINALLY_JUMP: 308 case VM_CONTEXT_TRY: 309 case VM_CONTEXT_CATCH: 310 { 311 return PARSER_TRY_CONTEXT_STACK_ALLOCATION; 312 } 313#if ENABLED (JERRY_ES2015) 314 case VM_CONTEXT_BLOCK: 315#endif /* ENABLED (JERRY_ES2015) */ 316 case VM_CONTEXT_WITH: 317 { 318 return PARSER_WITH_CONTEXT_STACK_ALLOCATION; 319 } 320#if ENABLED (JERRY_ES2015) 321 case VM_CONTEXT_FOR_OF: 322 { 323 return ((3 << (VM_CONTEXT_OFFSET_SHIFT * 2)) 324 | (2 << (VM_CONTEXT_OFFSET_SHIFT)) 325 | PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); 326 } 327#endif /* ENABLED (JERRY_ES2015) */ 328 default: 329 { 330 return (4 << (VM_CONTEXT_OFFSET_SHIFT)) | PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; 331 } 332 } 333} /* vm_get_context_value_offsets */ 334 335/** 336 * Ref / deref lexical environments in the chain using the current context. 337 */ 338void 339vm_ref_lex_env_chain (ecma_object_t *lex_env_p, /**< top of lexical environment */ 340 uint16_t context_depth, /**< depth of function context */ 341 ecma_value_t *context_end_p, /**< end of function context */ 342 bool do_ref) /**< ref or deref lexical environments */ 343{ 344 ecma_value_t *context_top_p = context_end_p + context_depth; 345 JERRY_ASSERT (context_top_p > context_end_p); 346 347 do 348 { 349 if (context_top_p[-1] & VM_CONTEXT_HAS_LEX_ENV) 350 { 351 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); 352 ecma_object_t *next_lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); 353 354 if (do_ref) 355 { 356 ecma_ref_object (lex_env_p); 357 } 358 else 359 { 360 ecma_deref_object (lex_env_p); 361 } 362 363 lex_env_p = next_lex_env_p; 364 } 365 366 uint32_t offsets = vm_get_context_value_offsets (context_top_p); 367 368 while (VM_CONTEXT_HAS_NEXT_OFFSET (offsets)) 369 { 370 int32_t offset = VM_CONTEXT_GET_NEXT_OFFSET (offsets); 371 372 if (do_ref) 373 { 374 ecma_ref_if_object (context_top_p[offset]); 375 } 376 else 377 { 378 ecma_deref_if_object (context_top_p[offset]); 379 } 380 381 offsets >>= VM_CONTEXT_OFFSET_SHIFT; 382 } 383 384 JERRY_ASSERT (context_top_p >= context_end_p + offsets); 385 context_top_p -= offsets; 386 } 387 while (context_top_p > context_end_p); 388} /* vm_ref_lex_env_chain */ 389 390#endif /* ENABLED (JERRY_ES2015) */ 391 392/** 393 * @} 394 * @} 395 */ 396