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
30 JERRY_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 */
38 ecma_value_t *
vm_stack_context_abort(vm_frame_ctx_t * frame_ctx_p,ecma_value_t * vm_stack_top_p)39 vm_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 */
126 static uint32_t
vm_decode_branch_offset(const uint8_t * branch_offset_p,uint32_t length)127 vm_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 */
159 bool
vm_stack_find_finally(vm_frame_ctx_t * frame_ctx_p,ecma_value_t ** vm_stack_top_ref_p,vm_stack_context_type_t finally_type,uint32_t search_limit)160 vm_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 */
297 uint32_t
vm_get_context_value_offsets(ecma_value_t * context_item_p)298 vm_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 */
338 void
vm_ref_lex_env_chain(ecma_object_t * lex_env_p,uint16_t context_depth,ecma_value_t * context_end_p,bool do_ref)339 vm_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