• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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