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 "jcontext.h"
17 #include "jerryscript.h"
18
19 #include "ecma-exceptions.h"
20 #include "ecma-function-object.h"
21 #include "ecma-gc.h"
22 #include "ecma-globals.h"
23 #include "ecma-helpers.h"
24 #include "ecma-lex-env.h"
25 #include "ecma-module.h"
26 #include "ecma-objects.h"
27 #include "lit-char-helpers.h"
28 #include "vm.h"
29
30 #if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
31
32 /**
33 * Takes a ModuleSpecifier and applies path normalization to it.
34 * It's not checked if the ModuleSpecifier is a valid path or not.
35 * Note: See 15.2.1.17
36 *
37 * @return pointer to ecma_string_t containing the normalized and zero terminated path
38 */
39 ecma_string_t *
ecma_module_create_normalized_path(const uint8_t * char_p,prop_length_t size)40 ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier */
41 prop_length_t size) /**< size of module specifier */
42 {
43 JERRY_ASSERT (size > 0);
44 ecma_string_t *ret_p = NULL;
45
46 /* The module specifier is cesu8 encoded, we need to convert is to utf8, and zero terminate it,
47 * so that OS level functions can handle it. */
48 lit_utf8_byte_t *path_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (size + 1u);
49
50 lit_utf8_size_t utf8_size;
51 utf8_size = lit_convert_cesu8_string_to_utf8_string (char_p,
52 size,
53 path_p,
54 size);
55 path_p[utf8_size] = LIT_CHAR_NULL;
56
57 lit_utf8_byte_t *module_path_p = NULL;
58 lit_utf8_size_t module_path_size = 0;
59
60 /* Check if we have a current module, and use its path as the base path. */
61 JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p) != NULL);
62 if (JERRY_CONTEXT (module_top_context_p)->module_p != NULL)
63 {
64 JERRY_ASSERT (JERRY_CONTEXT (module_top_context_p)->module_p->path_p != NULL);
65 module_path_size = ecma_string_get_size (JERRY_CONTEXT (module_top_context_p)->module_p->path_p);
66 module_path_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (module_path_size + 1);
67
68 lit_utf8_size_t module_utf8_size;
69 module_utf8_size = ecma_string_copy_to_utf8_buffer (JERRY_CONTEXT (module_top_context_p)->module_p->path_p,
70 module_path_p,
71 module_path_size);
72
73 module_path_p[module_utf8_size] = LIT_CHAR_NULL;
74 }
75
76 lit_utf8_byte_t *normalized_out_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (ECMA_MODULE_MAX_PATH);
77 size_t normalized_size = jerry_port_normalize_path ((const char *) path_p,
78 (char *) normalized_out_p,
79 ECMA_MODULE_MAX_PATH,
80 (char *) module_path_p);
81
82 if (normalized_size > 0)
83 {
84 /* Convert the normalized path to cesu8. */
85 ret_p = ecma_new_ecma_string_from_utf8_converted_to_cesu8 (normalized_out_p, (lit_utf8_size_t) (normalized_size));
86 }
87
88 jmem_heap_free_block (path_p, size + 1u);
89 jmem_heap_free_block (normalized_out_p, ECMA_MODULE_MAX_PATH);
90 if (module_path_p != NULL)
91 {
92 jmem_heap_free_block (module_path_p, module_path_size + 1);
93 }
94
95 return ret_p;
96 } /* ecma_module_create_normalized_path */
97
98 /**
99 * Find a module with a specific identifier
100 *
101 * @return pointer to ecma_module_t, if found
102 * NULL, otherwise
103 */
104 ecma_module_t *
ecma_module_find_module(ecma_string_t * const path_p)105 ecma_module_find_module (ecma_string_t *const path_p) /**< module identifier */
106 {
107 ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p);
108 while (current_p != NULL)
109 {
110 if (ecma_compare_ecma_strings (path_p, current_p->path_p))
111 {
112 return current_p;
113 }
114 current_p = current_p->next_p;
115 }
116
117 return current_p;
118 } /* ecma_module_find_module */
119
120 /**
121 * Create a new module
122 *
123 * @return pointer to created module
124 */
125 static ecma_module_t *
ecma_module_create_module(ecma_string_t * const path_p)126 ecma_module_create_module (ecma_string_t *const path_p) /**< module identifier */
127 {
128 ecma_module_t *module_p = (ecma_module_t *) jmem_heap_alloc_block (sizeof (ecma_module_t));
129 memset (module_p, 0, sizeof (ecma_module_t));
130
131 module_p->path_p = path_p;
132 module_p->next_p = JERRY_CONTEXT (ecma_modules_p);
133 JERRY_CONTEXT (ecma_modules_p) = module_p;
134 return module_p;
135 } /* ecma_module_create_module */
136
137 /**
138 * Checks if we already have a module request in the module list.
139 *
140 * @return pointer to found or newly created module structure
141 */
142 ecma_module_t *
ecma_module_find_or_create_module(ecma_string_t * const path_p)143 ecma_module_find_or_create_module (ecma_string_t *const path_p) /**< module path */
144 {
145 ecma_module_t *module_p = ecma_module_find_module (path_p);
146 if (module_p)
147 {
148 ecma_deref_ecma_string (path_p);
149 return module_p;
150 }
151
152 return ecma_module_create_module (path_p);
153 } /* ecma_module_find_or_create_module */
154
155 /**
156 * Create a new native module
157 *
158 * @return pointer to created module
159 */
160 ecma_module_t *
ecma_module_create_native_module(ecma_string_t * const path_p,ecma_object_t * const namespace_p)161 ecma_module_create_native_module (ecma_string_t *const path_p, /**< module identifier */
162 ecma_object_t *const namespace_p) /**< module namespace */
163 {
164 ecma_module_t *module_p = ecma_module_create_module (path_p);
165 module_p->state = ECMA_MODULE_STATE_NATIVE;
166 module_p->namespace_object_p = namespace_p;
167 return module_p;
168 } /* ecma_module_create_native_module */
169
170 /**
171 * Creates a module context.
172 *
173 * @return pointer to created module context
174 */
175 static ecma_module_context_t *
ecma_module_create_module_context(void)176 ecma_module_create_module_context (void)
177 {
178 ecma_module_context_t *context_p = (ecma_module_context_t *) jmem_heap_alloc_block (sizeof (ecma_module_context_t));
179 memset (context_p, 0, sizeof (ecma_module_context_t));
180
181 return context_p;
182 } /* ecma_module_create_module_context */
183
184 /**
185 * Inserts a {module, export_name} record into a resolve set.
186 * Note: See 15.2.1.16.3 - resolveSet and exportStarSet
187 *
188 * @return true - if the set already contains the record
189 * false - otherwise
190 */
191 bool
ecma_module_resolve_set_insert(ecma_module_resolve_set_t ** set_p,ecma_module_t * const module_p,ecma_string_t * const export_name_p)192 ecma_module_resolve_set_insert (ecma_module_resolve_set_t **set_p, /**< [in, out] resolve set */
193 ecma_module_t * const module_p, /**< module */
194 ecma_string_t * const export_name_p) /**< export name */
195 {
196 JERRY_ASSERT (set_p != NULL);
197 ecma_module_resolve_set_t *current_p = *set_p;
198
199 while (current_p != NULL)
200 {
201 if (current_p->record.module_p == module_p
202 && ecma_compare_ecma_strings (current_p->record.name_p, export_name_p))
203 {
204 return false;
205 }
206
207 current_p = current_p->next_p;
208 }
209
210 ecma_module_resolve_set_t *new_p;
211 new_p = (ecma_module_resolve_set_t *) jmem_heap_alloc_block (sizeof (ecma_module_resolve_set_t));
212
213 new_p->next_p = *set_p;
214 new_p->record.module_p = module_p;
215 ecma_ref_ecma_string (export_name_p);
216 new_p->record.name_p = export_name_p;
217
218 *set_p = new_p;
219 return true;
220 } /* ecma_module_resolve_set_insert */
221
222 /**
223 * Cleans up contents of a resolve set.
224 */
225 void
ecma_module_resolve_set_cleanup(ecma_module_resolve_set_t * set_p)226 ecma_module_resolve_set_cleanup (ecma_module_resolve_set_t *set_p) /**< resolve set */
227 {
228 while (set_p != NULL)
229 {
230 ecma_module_resolve_set_t *next_p = set_p->next_p;
231 ecma_deref_ecma_string (set_p->record.name_p);
232 jmem_heap_free_block (set_p, sizeof (ecma_module_resolve_set_t));
233 set_p = next_p;
234 }
235 } /* ecma_module_resolve_set_cleanup */
236
237 /**
238 * Pushes a new resolve frame on top of a resolve stack and initializes it
239 * to begin resolving the specified exported name in the base module.
240 */
241 void
ecma_module_resolve_stack_push(ecma_module_resolve_stack_t ** stack_p,ecma_module_t * const module_p,ecma_string_t * const export_name_p)242 ecma_module_resolve_stack_push (ecma_module_resolve_stack_t **stack_p, /**< [in, out] resolve stack */
243 ecma_module_t * const module_p, /**< base module */
244 ecma_string_t * const export_name_p) /**< exported name */
245 {
246 JERRY_ASSERT (stack_p != NULL);
247 ecma_module_resolve_stack_t *new_frame_p;
248 new_frame_p = (ecma_module_resolve_stack_t *) jmem_heap_alloc_block (sizeof (ecma_module_resolve_stack_t));
249
250 ecma_ref_ecma_string (export_name_p);
251 new_frame_p->export_name_p = export_name_p;
252 new_frame_p->module_p = module_p;
253 new_frame_p->resolving = false;
254
255 new_frame_p->next_p = *stack_p;
256 *stack_p = new_frame_p;
257 } /* ecma_module_resolve_stack_push */
258
259 /**
260 * Pops the topmost frame from a resolve stack.
261 */
262 void
ecma_module_resolve_stack_pop(ecma_module_resolve_stack_t ** stack_p)263 ecma_module_resolve_stack_pop (ecma_module_resolve_stack_t **stack_p) /**< [in, out] resolve stack */
264 {
265 JERRY_ASSERT (stack_p != NULL);
266 ecma_module_resolve_stack_t *current_p = *stack_p;
267
268 if (current_p != NULL)
269 {
270 *stack_p = current_p->next_p;
271 ecma_deref_ecma_string (current_p->export_name_p);
272 jmem_heap_free_block (current_p, sizeof (ecma_module_resolve_stack_t));
273 }
274 } /* ecma_module_resolve_stack_pop */
275
276 /**
277 * Resolves which module satisfies an export based from a specific module in the import tree.
278 * If no error occurs, out_record_p will contain a {module, local_name} record, which satisfies
279 * the export, or {NULL, NULL} if the export is ambiguous.
280 * Note: See 15.2.1.16.3
281 *
282 * @return ECMA_VALUE_ERROR - if an error occured
283 * ECMA_VALUE_EMPTY - otherwise
284 */
285 static ecma_value_t
ecma_module_resolve_export(ecma_module_t * const module_p,ecma_string_t * const export_name_p,ecma_module_record_t * out_record_p)286 ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */
287 ecma_string_t * const export_name_p, /**< export name */
288 ecma_module_record_t *out_record_p) /**< [out] found module record */
289 {
290 ecma_module_resolve_set_t *resolve_set_p = NULL;
291 ecma_module_resolve_stack_t *stack_p = NULL;
292
293 bool found = false;
294 ecma_module_record_t found_record = { NULL, NULL };
295 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
296
297 ecma_module_resolve_stack_push (&stack_p, module_p, export_name_p);
298
299 while (stack_p != NULL)
300 {
301 ecma_module_resolve_stack_t *current_frame_p = stack_p;
302
303 ecma_module_t *current_module_p = current_frame_p->module_p;
304 JERRY_ASSERT (current_module_p->state >= ECMA_MODULE_STATE_PARSED);
305 ecma_module_context_t *context_p = current_module_p->context_p;
306 ecma_string_t *current_export_name_p = current_frame_p->export_name_p;
307
308 if (!current_frame_p->resolving)
309 {
310 current_frame_p->resolving = true;
311
312 /* 15.2.1.16.3 / 2-3 */
313 if (!ecma_module_resolve_set_insert (&resolve_set_p, current_module_p, current_export_name_p))
314 {
315 /* This is a circular import request. */
316 ecma_module_resolve_stack_pop (&stack_p);
317 continue;
318 }
319
320 if (current_module_p->state == ECMA_MODULE_STATE_NATIVE)
321 {
322 ecma_object_t *object_p = current_module_p->namespace_object_p;
323 ecma_value_t prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p),
324 object_p,
325 current_export_name_p);
326 if (ecma_is_value_found (prop_value))
327 {
328 found = true;
329 found_record.module_p = current_module_p;
330 found_record.name_p = current_export_name_p;
331 ecma_free_value (prop_value);
332 }
333
334 if (ecma_compare_ecma_string_to_magic_id (current_export_name_p, LIT_MAGIC_STRING_DEFAULT))
335 {
336 ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("No default export in native module."));
337 break;
338 }
339
340 ecma_module_resolve_stack_pop (&stack_p);
341 continue;
342 }
343
344 if (context_p->local_exports_p != NULL)
345 {
346 /* 15.2.1.16.3 / 4 */
347 JERRY_ASSERT (context_p->local_exports_p->next_p == NULL);
348 ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p;
349 while (export_names_p != NULL)
350 {
351 if (ecma_compare_ecma_strings (current_export_name_p, export_names_p->imex_name_p))
352 {
353 if (found)
354 {
355 /* This is an ambigous export. */
356 found_record.module_p = NULL;
357 found_record.name_p = NULL;
358 break;
359 }
360
361 /* The current module provides a direct binding for this export. */
362 found = true;
363 found_record.module_p = current_module_p;
364 found_record.name_p = export_names_p->local_name_p;
365 break;
366 }
367
368 export_names_p = export_names_p->next_p;
369 }
370 }
371
372 if (found)
373 {
374 /* We found a resolution for the current frame, return to the previous. */
375 ecma_module_resolve_stack_pop (&stack_p);
376 continue;
377 }
378
379 /* 15.2.1.16.3 / 5 */
380 ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p;
381 while (indirect_export_p != NULL)
382 {
383 ecma_module_names_t *export_names_p = indirect_export_p->module_names_p;
384 while (export_names_p != NULL)
385 {
386 if (ecma_compare_ecma_strings (current_export_name_p, export_names_p->imex_name_p))
387 {
388 /* 5.2.1.16.3 / 5.a.iv */
389 ecma_module_resolve_stack_push (&stack_p,
390 indirect_export_p->module_request_p,
391 export_names_p->local_name_p);
392 }
393
394 export_names_p = export_names_p->next_p;
395 }
396
397 indirect_export_p = indirect_export_p->next_p;
398 }
399
400 /* We need to check whether the newly pushed indirect exports resolve to anything.
401 * Keep current frame in the stack, and continue from the topmost frame. */
402 continue;
403 } /* if (!current_frame_p->resolving) */
404
405 /* By the time we return to the current frame, the indirect exports will have finished resolving. */
406 if (found)
407 {
408 /* We found at least one export that satisfies the current request.
409 * Pop current frame, and return to the previous. */
410 ecma_module_resolve_stack_pop (&stack_p);
411 continue;
412 }
413
414 /* 15.2.1.16.3 / 6 */
415 if (ecma_compare_ecma_string_to_magic_id (current_export_name_p, LIT_MAGIC_STRING_DEFAULT))
416 {
417 ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("No explicitly defined default export in module."));
418 break;
419 }
420
421 /* 15.2.1.16.3 / 7-8 */
422 if (!ecma_module_resolve_set_insert (&resolve_set_p,
423 current_module_p,
424 ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR)))
425 {
426 /* This is a circular import request. */
427 ecma_module_resolve_stack_pop (&stack_p);
428 continue;
429 }
430
431 /* Pop the current frame, we have nothing else to do here after the star export resolutions are queued. */
432 ecma_module_resolve_stack_pop (&stack_p);
433
434 /* 15.2.1.16.3 / 10 */
435 ecma_module_node_t *star_export_p = context_p->star_exports_p;
436 while (star_export_p != NULL)
437 {
438 JERRY_ASSERT (star_export_p->module_names_p == NULL);
439
440 /* 15.2.1.16.3 / 10.c */
441 ecma_module_resolve_stack_push (&stack_p, star_export_p->module_request_p, export_name_p);
442
443 star_export_p = star_export_p->next_p;
444 }
445 }
446
447 /* Clean up. */
448 ecma_module_resolve_set_cleanup (resolve_set_p);
449 while (stack_p)
450 {
451 ecma_module_resolve_stack_pop (&stack_p);
452 }
453
454 if (ECMA_IS_VALUE_ERROR (ret_value))
455 {
456 /* No default export was found */
457 return ret_value;
458 }
459
460 if (found)
461 {
462 *out_record_p = found_record;
463 }
464 else
465 {
466 ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexported or circular import request."));
467 }
468
469 return ret_value;
470 } /* ecma_module_resolve_export */
471
472 /**
473 * Resolves an export and adds it to the modules namespace object, if the export name is not yet handled.
474 * Note: See 15.2.1.16.2 and 15.2.1.18
475 *
476 * @return ECMA_VALUE_ERROR - if an error occured
477 * ECMA_VALUE_EMPTY - otherwise
478 */
479 static ecma_value_t
ecma_module_namespace_object_add_export_if_needed(ecma_module_t * module_p,ecma_string_t * export_name_p)480 ecma_module_namespace_object_add_export_if_needed (ecma_module_t *module_p, /**< module */
481 ecma_string_t *export_name_p) /**< export name */
482 {
483 JERRY_ASSERT (module_p->namespace_object_p != NULL);
484 ecma_value_t result = ECMA_VALUE_EMPTY;
485
486 if (ecma_find_named_property (module_p->namespace_object_p, export_name_p) != NULL)
487 {
488 /* This export name has already been handled. */
489 return result;
490 }
491
492 ecma_module_record_t record;
493 result = ecma_module_resolve_export (module_p, export_name_p, &record);
494
495 if (ECMA_IS_VALUE_ERROR (result))
496 {
497 return result;
498 }
499
500 if (record.module_p == NULL)
501 {
502 /* 15.2.1.18 / 3.d.iv Skip ambiguous names. */
503 return result;
504 }
505
506 ecma_object_t *ref_base_lex_env_p;
507 ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p,
508 &ref_base_lex_env_p,
509 record.name_p);
510 ecma_property_t *new_property_p;
511 ecma_create_named_data_property (module_p->namespace_object_p,
512 export_name_p,
513 ECMA_PROPERTY_FIXED,
514 &new_property_p);
515
516 ecma_named_data_property_assign_value (module_p->namespace_object_p,
517 ECMA_PROPERTY_VALUE_PTR (new_property_p),
518 prop_value);
519
520 ecma_free_value (prop_value);
521 return result;
522 } /* ecma_module_namespace_object_add_export_if_needed */
523
524 /**
525 * Creates a namespace object for a module.
526 * Note: See 15.2.1.18
527 *
528 * @return ECMA_VALUE_ERROR - if an error occured
529 * ECMA_VALUE_EMPTY - otherwise
530 */
531 static ecma_value_t
ecma_module_create_namespace_object(ecma_module_t * module_p)532 ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */
533 {
534 ecma_value_t result = ECMA_VALUE_EMPTY;
535 if (module_p->namespace_object_p != NULL)
536 {
537 return result;
538 }
539
540 JERRY_ASSERT (module_p->state == ECMA_MODULE_STATE_EVALUATED);
541 ecma_module_resolve_set_t *resolve_set_p = NULL;
542 ecma_module_resolve_stack_t *stack_p = NULL;
543
544 module_p->namespace_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
545 0,
546 ECMA_OBJECT_TYPE_GENERAL);
547
548 ecma_module_resolve_stack_push (&stack_p, module_p, ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR));
549 while (stack_p != NULL)
550 {
551 ecma_module_resolve_stack_t *current_frame_p = stack_p;
552 ecma_module_t *current_module_p = current_frame_p->module_p;
553 ecma_module_context_t *context_p = current_module_p->context_p;
554
555 ecma_module_resolve_stack_pop (&stack_p);
556
557 /* 15.2.1.16.2 / 2-3 */
558 if (!ecma_module_resolve_set_insert (&resolve_set_p,
559 current_module_p,
560 ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR)))
561 {
562 /* Circular import. */
563 continue;
564 }
565
566 if (context_p->local_exports_p != NULL)
567 {
568 /* 15.2.1.16.2 / 5 */
569 JERRY_ASSERT (context_p->local_exports_p->next_p == NULL);
570 ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p;
571 while (export_names_p != NULL && ecma_is_value_empty (result))
572 {
573 result = ecma_module_namespace_object_add_export_if_needed (module_p,
574 export_names_p->imex_name_p);
575 export_names_p = export_names_p->next_p;
576 }
577 }
578
579 /* 15.2.1.16.2 / 6 */
580 ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p;
581 while (indirect_export_p != NULL && ecma_is_value_empty (result))
582 {
583 ecma_module_names_t *export_names_p = indirect_export_p->module_names_p;
584 while (export_names_p != NULL && ecma_is_value_empty (result))
585 {
586 result = ecma_module_namespace_object_add_export_if_needed (module_p,
587 export_names_p->imex_name_p);
588 export_names_p = export_names_p->next_p;
589 }
590 indirect_export_p = indirect_export_p->next_p;
591 }
592
593 /* 15.2.1.16.2 / 7 */
594 ecma_module_node_t *star_export_p = context_p->star_exports_p;
595 while (star_export_p != NULL && ecma_is_value_empty (result))
596 {
597 JERRY_ASSERT (star_export_p->module_names_p == NULL);
598
599 /* 15.2.1.16.3/10.c */
600 ecma_module_resolve_stack_push (&stack_p,
601 star_export_p->module_request_p,
602 ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR));
603
604 star_export_p = star_export_p->next_p;
605 }
606 }
607
608 /* Clean up. */
609 ecma_module_resolve_set_cleanup (resolve_set_p);
610 while (stack_p)
611 {
612 ecma_module_resolve_stack_pop (&stack_p);
613 }
614
615 return result;
616 } /* ecma_module_create_namespace_object */
617
618 /**
619 * Evaluates an EcmaScript module.
620 *
621 * @return ECMA_VALUE_ERROR - if an error occured
622 * ECMA_VALUE_EMPTY - otherwise
623 */
624 static ecma_value_t
ecma_module_evaluate(ecma_module_t * module_p)625 ecma_module_evaluate (ecma_module_t *module_p) /**< module */
626 {
627 JERRY_ASSERT (module_p->state >= ECMA_MODULE_STATE_PARSED);
628
629 if (module_p->state >= ECMA_MODULE_STATE_EVALUATING)
630 {
631 return ECMA_VALUE_EMPTY;
632 }
633
634 module_p->state = ECMA_MODULE_STATE_EVALUATING;
635 module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ());
636 module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p);
637 JERRY_CONTEXT (module_top_context_p) = module_p->context_p;
638
639 ecma_value_t ret_value;
640 ret_value = vm_run_module (module_p->compiled_code_p,
641 module_p->scope_p);
642
643 if (!ECMA_IS_VALUE_ERROR (ret_value))
644 {
645 jerry_release_value (ret_value);
646 ret_value = ECMA_VALUE_EMPTY;
647 }
648
649 JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p;
650
651 ecma_bytecode_deref (module_p->compiled_code_p);
652 module_p->state = ECMA_MODULE_STATE_EVALUATED;
653
654 return ret_value;
655 } /* ecma_module_evaluate */
656
657 /**
658 * Connects imported values to the current context.
659 *
660 * @return ECMA_VALUE_ERROR - if an error occured
661 * ECMA_VALUE_EMPTY - otherwise
662 */
663 static ecma_value_t
ecma_module_connect_imports(void)664 ecma_module_connect_imports (void)
665 {
666 ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p);
667
668 ecma_object_t *local_env_p = current_context_p->module_p->scope_p;
669 JERRY_ASSERT (ecma_is_lexical_environment (local_env_p));
670
671 ecma_module_node_t *import_node_p = current_context_p->imports_p;
672
673 /* Check that the imported bindings don't exist yet. */
674 while (import_node_p != NULL)
675 {
676 ecma_module_names_t *import_names_p = import_node_p->module_names_p;
677
678 while (import_names_p != NULL)
679 {
680 ecma_object_t *lex_env_p = local_env_p;
681 ecma_property_t *binding_p = NULL;
682
683 if (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK)
684 {
685 binding_p = ecma_find_named_property (lex_env_p, import_names_p->local_name_p);
686
687 JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
688 lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
689 }
690
691 if (binding_p != NULL)
692 {
693 return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable."));
694 }
695
696 ecma_value_t status = ecma_op_has_binding (lex_env_p, import_names_p->local_name_p);
697
698 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
699 if (ECMA_IS_VALUE_ERROR (status))
700 {
701 return status;
702 }
703 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
704
705 if (ecma_is_value_true (status))
706 {
707 return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable."));
708 }
709
710 import_names_p = import_names_p->next_p;
711 }
712
713 import_node_p = import_node_p->next_p;
714 }
715
716 import_node_p = current_context_p->imports_p;
717
718 /* Resolve imports and create local bindings. */
719 while (import_node_p != NULL)
720 {
721 ecma_value_t result = ecma_module_evaluate (import_node_p->module_request_p);
722 if (ECMA_IS_VALUE_ERROR (result))
723 {
724 return result;
725 }
726
727 ecma_module_names_t *import_names_p = import_node_p->module_names_p;
728 while (import_names_p != NULL)
729 {
730 const bool is_namespace_import = ecma_compare_ecma_string_to_magic_id (import_names_p->imex_name_p,
731 LIT_MAGIC_STRING_ASTERIX_CHAR);
732
733 if (is_namespace_import)
734 {
735 result = ecma_module_create_namespace_object (import_node_p->module_request_p);
736 if (ECMA_IS_VALUE_ERROR (result))
737 {
738 return result;
739 }
740
741 ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
742 ecma_op_set_mutable_binding (local_env_p,
743 import_names_p->local_name_p,
744 ecma_make_object_value (import_node_p->module_request_p->namespace_object_p),
745 false /* is_strict */);
746 }
747 else /* !is_namespace_import */
748 {
749 ecma_module_record_t record;
750 result = ecma_module_resolve_export (import_node_p->module_request_p, import_names_p->imex_name_p, &record);
751
752 if (ECMA_IS_VALUE_ERROR (result))
753 {
754 return result;
755 }
756
757 if (record.module_p == NULL)
758 {
759 return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous import request."));
760 }
761
762 if (record.module_p->state == ECMA_MODULE_STATE_NATIVE)
763 {
764 ecma_object_t *object_p = record.module_p->namespace_object_p;
765 ecma_value_t prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p),
766 object_p,
767 record.name_p);
768 JERRY_ASSERT (ecma_is_value_found (prop_value));
769
770 ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
771 ecma_op_set_mutable_binding (local_env_p,
772 import_names_p->local_name_p,
773 prop_value,
774 false /* is_strict */);
775
776 ecma_free_value (prop_value);
777 }
778 else
779 {
780 result = ecma_module_evaluate (record.module_p);
781
782 if (ECMA_IS_VALUE_ERROR (result))
783 {
784 return result;
785 }
786
787 ecma_object_t *ref_base_lex_env_p;
788 ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p,
789 &ref_base_lex_env_p,
790 record.name_p);
791
792 ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */);
793 ecma_op_set_mutable_binding (local_env_p,
794 import_names_p->local_name_p,
795 prop_value,
796 false /* is_strict */);
797
798 ecma_free_value (prop_value);
799 }
800 }
801
802 import_names_p = import_names_p->next_p;
803 }
804
805 import_node_p = import_node_p->next_p;
806 }
807
808 return ECMA_VALUE_EMPTY;
809 } /* ecma_module_connect_imports */
810
811 /**
812 * Initialize the current module by creating the local binding for the imported variables
813 * and verifying indirect exports.
814 *
815 * @return ECMA_VALUE_ERROR - if an error occured
816 * ECMA_VALUE_EMPTY - otherwise
817 */
818 ecma_value_t
ecma_module_initialize_current(void)819 ecma_module_initialize_current (void)
820 {
821 ecma_value_t ret_value = ecma_module_connect_imports ();
822
823 if (ecma_is_value_empty (ret_value))
824 {
825 ret_value = ecma_module_check_indirect_exports ();
826 }
827
828 return ret_value;
829 } /* ecma_module_initialize_current */
830
831 /**
832 * Parses an EcmaScript module.
833 *
834 * @return ECMA_VALUE_ERROR - if an error occured
835 * ECMA_VALUE_EMPTY - otherwise
836 */
837 static jerry_value_t
ecma_module_parse(ecma_module_t * module_p)838 ecma_module_parse (ecma_module_t *module_p) /**< module */
839 {
840 if (module_p->state >= ECMA_MODULE_STATE_PARSING)
841 {
842 return ECMA_VALUE_EMPTY;
843 }
844
845 module_p->state = ECMA_MODULE_STATE_PARSING;
846 module_p->context_p = ecma_module_create_module_context ();
847
848 lit_utf8_size_t module_path_size = ecma_string_get_size (module_p->path_p);
849 lit_utf8_byte_t *module_path_p = (lit_utf8_byte_t *) jmem_heap_alloc_block (module_path_size + 1);
850
851 lit_utf8_size_t module_path_utf8_size;
852 module_path_utf8_size = ecma_string_copy_to_utf8_buffer (module_p->path_p,
853 module_path_p,
854 module_path_size);
855 module_path_p[module_path_utf8_size] = LIT_CHAR_NULL;
856
857 size_t source_size = 0;
858 uint8_t *source_p = jerry_port_read_source ((const char *) module_path_p, &source_size);
859 jmem_heap_free_block (module_path_p, module_path_size + 1);
860
861 if (source_p == NULL)
862 {
863 return ecma_raise_syntax_error (ECMA_ERR_MSG ("File not found."));
864 }
865
866 module_p->context_p->module_p = module_p;
867 module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p);
868 JERRY_CONTEXT (module_top_context_p) = module_p->context_p;
869
870 #if ENABLED (JERRY_DEBUGGER) && ENABLED (JERRY_PARSER)
871 if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
872 {
873 jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME,
874 JERRY_DEBUGGER_NO_SUBTYPE,
875 module_path_p,
876 module_path_size - 1);
877 }
878 #endif /* ENABLED (JERRY_DEBUGGER) && ENABLED (JERRY_PARSER) */
879
880 JERRY_CONTEXT (resource_name) = ecma_make_string_value (module_p->path_p);
881
882 ecma_compiled_code_t *bytecode_data_p;
883 ecma_value_t ret_value = parser_parse_script (NULL,
884 0,
885 (jerry_char_t *) source_p,
886 source_size,
887 ECMA_PARSE_STRICT_MODE | ECMA_PARSE_MODULE,
888 &bytecode_data_p);
889
890 JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p;
891
892 jerry_port_release_source (source_p);
893
894 if (ECMA_IS_VALUE_ERROR (ret_value))
895 {
896 return ret_value;
897 }
898
899 ecma_free_value (ret_value);
900
901 module_p->compiled_code_p = bytecode_data_p;
902 module_p->state = ECMA_MODULE_STATE_PARSED;
903
904 return ECMA_VALUE_EMPTY;
905 } /* ecma_module_parse */
906
907 /**
908 * Parses all referenced modules.
909 *
910 * @return ECMA_VALUE_ERROR - if an error occured
911 * ECMA_VALUE_EMPTY - otherwise
912 */
913 ecma_value_t
ecma_module_parse_modules(void)914 ecma_module_parse_modules (void)
915 {
916 ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p);
917
918 while (current_p != NULL)
919 {
920 ecma_value_t ret_value = ecma_module_parse (current_p);
921 if (ECMA_IS_VALUE_ERROR (ret_value))
922 {
923 return ret_value;
924 }
925
926 JERRY_ASSERT (ecma_is_value_empty (ret_value));
927 current_p = current_p->next_p;
928 }
929
930 return ECMA_VALUE_EMPTY;
931 } /* ecma_module_parse_modules */
932
933 /**
934 * Checks if indirect exports in the current context are resolvable.
935 * Note: See 15.2.1.16.4 / 9.
936 *
937 * @return ECMA_VALUE_ERROR - if an error occured
938 * ECMA_VALUE_EMPTY - otherwise
939 */
940 ecma_value_t
ecma_module_check_indirect_exports(void)941 ecma_module_check_indirect_exports (void)
942 {
943 ecma_module_node_t *indirect_export_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p;
944 while (indirect_export_p != NULL)
945 {
946 ecma_module_names_t *name_p = indirect_export_p->module_names_p;
947 while (name_p != NULL)
948 {
949 ecma_module_record_t record;
950 ecma_value_t result = ecma_module_resolve_export (indirect_export_p->module_request_p,
951 name_p->local_name_p,
952 &record);
953
954 if (ECMA_IS_VALUE_ERROR (result))
955 {
956 return result;
957 }
958
959 if (record.module_p == NULL)
960 {
961 return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous indirect export request."));
962 }
963
964 name_p = name_p->next_p;
965 }
966
967 indirect_export_p = indirect_export_p->next_p;
968 }
969
970 return ECMA_VALUE_EMPTY;
971 } /* ecma_module_check_indirect_exports */
972
973 /**
974 * Cleans up a list of module names.
975 */
976 static void
ecma_module_release_module_names(ecma_module_names_t * module_name_p)977 ecma_module_release_module_names (ecma_module_names_t *module_name_p) /**< first module name */
978 {
979 while (module_name_p != NULL)
980 {
981 ecma_module_names_t *next_p = module_name_p->next_p;
982
983 ecma_deref_ecma_string (module_name_p->imex_name_p);
984 ecma_deref_ecma_string (module_name_p->local_name_p);
985 jmem_heap_free_block (module_name_p, sizeof (ecma_module_names_t));
986
987 module_name_p = next_p;
988 }
989 } /* ecma_module_release_module_names */
990
991 /**
992 * Cleans up a list of module nodes.
993 */
994 void
ecma_module_release_module_nodes(ecma_module_node_t * module_node_p)995 ecma_module_release_module_nodes (ecma_module_node_t *module_node_p) /**< first module node */
996 {
997 while (module_node_p != NULL)
998 {
999 ecma_module_node_t *next_p = module_node_p->next_p;
1000
1001 ecma_module_release_module_names (module_node_p->module_names_p);
1002 jmem_heap_free_block (module_node_p, sizeof (ecma_module_node_t));
1003
1004 module_node_p = next_p;
1005 }
1006 } /* ecma_module_release_module_nodes */
1007
1008 /**
1009 * Cleans up a module context.
1010 */
1011 static void
ecma_module_release_module_context(ecma_module_context_t * module_context_p)1012 ecma_module_release_module_context (ecma_module_context_t *module_context_p) /**< modle context */
1013 {
1014 ecma_module_release_module_nodes (module_context_p->imports_p);
1015 ecma_module_release_module_nodes (module_context_p->local_exports_p);
1016 ecma_module_release_module_nodes (module_context_p->indirect_exports_p);
1017 ecma_module_release_module_nodes (module_context_p->star_exports_p);
1018
1019 jmem_heap_free_block (module_context_p, sizeof (ecma_module_context_t));
1020 } /* ecma_module_release_module_context */
1021
1022 /**
1023 * Cleans up a module structure.
1024 */
1025 static void
ecma_module_release_module(ecma_module_t * module_p)1026 ecma_module_release_module (ecma_module_t *module_p) /**< module */
1027 {
1028 ecma_deref_ecma_string (module_p->path_p);
1029
1030 if (module_p->namespace_object_p != NULL)
1031 {
1032 ecma_deref_object (module_p->namespace_object_p);
1033 }
1034
1035 if (module_p->state == ECMA_MODULE_STATE_NATIVE)
1036 {
1037 goto finished;
1038 }
1039
1040 if (module_p->state >= ECMA_MODULE_STATE_PARSING)
1041 {
1042 ecma_module_release_module_context (module_p->context_p);
1043 }
1044
1045 if (module_p->state >= ECMA_MODULE_STATE_EVALUATING
1046 && module_p->scope_p != NULL)
1047 {
1048 ecma_deref_object (module_p->scope_p);
1049 }
1050
1051 if (module_p->state >= ECMA_MODULE_STATE_PARSED
1052 && module_p->state < ECMA_MODULE_STATE_EVALUATED)
1053 {
1054 ecma_bytecode_deref (module_p->compiled_code_p);
1055 }
1056
1057 finished:
1058 jmem_heap_free_block (module_p, sizeof (ecma_module_t));
1059 } /* ecma_module_release_module */
1060
1061 /**
1062 * Cleans up all modules if the current context is the root context.
1063 */
1064 void
ecma_module_cleanup(void)1065 ecma_module_cleanup (void)
1066 {
1067 ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p);
1068 while (current_p != NULL)
1069 {
1070 ecma_module_t *next_p = current_p->next_p;
1071 ecma_module_release_module (current_p);
1072 current_p = next_p;
1073 }
1074
1075 JERRY_CONTEXT (ecma_modules_p) = NULL;
1076 JERRY_CONTEXT (module_top_context_p) = NULL;
1077 } /* ecma_module_cleanup */
1078
1079 #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
1080