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 "config.h"
17 #include "jerryscript.h"
18
19 #include "test-common.h"
20
21 /**
22 * Maximum size of snapshots buffer
23 */
24 #define SNAPSHOT_BUFFER_SIZE (256)
25
26 /**
27 * Maximum size of literal buffer
28 */
29 #define LITERAL_BUFFER_SIZE (256)
30
31 /**
32 * Magic strings
33 */
34 static const jerry_char_t *magic_strings[] =
35 {
36 (const jerry_char_t *) " ",
37 (const jerry_char_t *) "a",
38 (const jerry_char_t *) "b",
39 (const jerry_char_t *) "c",
40 (const jerry_char_t *) "from",
41 (const jerry_char_t *) "func",
42 (const jerry_char_t *) "string",
43 (const jerry_char_t *) "snapshot"
44 };
45
46 /**
47 * Magic string lengths
48 */
49 static const jerry_length_t magic_string_lengths[] =
50 {
51 1, 1, 1, 1, 4, 4, 6, 8
52 };
53
test_function_snapshot(void)54 static void test_function_snapshot (void)
55 {
56 /* function to snapshot */
57 if (!jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
58 || !jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
59 {
60 return;
61 }
62
63 const jerry_init_flag_t flags = JERRY_INIT_EMPTY;
64 static uint32_t function_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
65
66 const jerry_char_t func_args[] = "a, b";
67 const jerry_char_t code_to_snapshot[] = "return a + b";
68
69 jerry_init (flags);
70 jerry_value_t generate_result;
71 generate_result = jerry_generate_function_snapshot (NULL,
72 0,
73 code_to_snapshot,
74 sizeof (code_to_snapshot) - 1,
75 func_args,
76 sizeof (func_args) - 1,
77 0,
78 function_snapshot_buffer,
79 SNAPSHOT_BUFFER_SIZE);
80 TEST_ASSERT (!jerry_value_is_error (generate_result)
81 && jerry_value_is_number (generate_result));
82
83 size_t function_snapshot_size = (size_t) jerry_get_number_value (generate_result);
84 jerry_release_value (generate_result);
85
86 jerry_cleanup ();
87
88 jerry_init (flags);
89
90 jerry_value_t function_obj = jerry_load_function_snapshot (function_snapshot_buffer,
91 function_snapshot_size,
92 0,
93 0);
94
95 TEST_ASSERT (!jerry_value_is_error (function_obj));
96 TEST_ASSERT (jerry_value_is_function (function_obj));
97
98 jerry_value_t this_val = jerry_create_undefined ();
99 jerry_value_t args[2];
100 args[0] = jerry_create_number (1.0);
101 args[1] = jerry_create_number (2.0);
102
103 jerry_value_t res = jerry_call_function (function_obj, this_val, args, 2);
104
105 TEST_ASSERT (!jerry_value_is_error (res));
106 TEST_ASSERT (jerry_value_is_number (res));
107 double num = jerry_get_number_value (res);
108 TEST_ASSERT (num == 3);
109
110 jerry_release_value (args[0]);
111 jerry_release_value (args[1]);
112 jerry_release_value (res);
113 jerry_release_value (function_obj);
114
115 jerry_cleanup ();
116 } /* test_function_snapshot */
117
arguments_test_exec_snapshot(uint32_t * snapshot_p,size_t snapshot_size,uint32_t exec_snapshot_flags)118 static void arguments_test_exec_snapshot (uint32_t *snapshot_p, size_t snapshot_size, uint32_t exec_snapshot_flags)
119 {
120 jerry_init (JERRY_INIT_EMPTY);
121 jerry_value_t res = jerry_exec_snapshot (snapshot_p, snapshot_size, 0, exec_snapshot_flags);
122 TEST_ASSERT (!jerry_value_is_error (res));
123 TEST_ASSERT (jerry_value_is_number (res));
124 double raw_value = jerry_get_number_value (res);
125 TEST_ASSERT (raw_value == 15);
126 jerry_release_value (res);
127
128 jerry_cleanup ();
129 } /* arguments_test_exec_snapshot */
130
test_function_arguments_snapshot(void)131 static void test_function_arguments_snapshot (void)
132 {
133 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
134 && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
135 {
136 static uint32_t arguments_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
137
138 const jerry_char_t code_to_snapshot[] = TEST_STRING_LITERAL (
139 "function f(a,b,c) {"
140 " arguments[0]++;"
141 " arguments[1]++;"
142 " arguments[2]++;"
143 " return a + b + c;"
144 "}"
145 "f(3,4,5);"
146 );
147 jerry_init (JERRY_INIT_EMPTY);
148
149 jerry_value_t generate_result;
150 generate_result = jerry_generate_snapshot (NULL,
151 0,
152 code_to_snapshot,
153 sizeof (code_to_snapshot) - 1,
154 0,
155 arguments_snapshot_buffer,
156 SNAPSHOT_BUFFER_SIZE);
157
158 TEST_ASSERT (!jerry_value_is_error (generate_result)
159 && jerry_value_is_number (generate_result));
160
161 size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
162 jerry_release_value (generate_result);
163
164 jerry_cleanup ();
165
166 arguments_test_exec_snapshot (arguments_snapshot_buffer, snapshot_size, 0);
167 arguments_test_exec_snapshot (arguments_snapshot_buffer, snapshot_size, JERRY_SNAPSHOT_EXEC_COPY_DATA);
168 }
169 } /* test_function_arguments_snapshot */
170
test_exec_snapshot(uint32_t * snapshot_p,size_t snapshot_size,uint32_t exec_snapshot_flags)171 static void test_exec_snapshot (uint32_t *snapshot_p, size_t snapshot_size, uint32_t exec_snapshot_flags)
172 {
173 char string_data[32];
174
175 jerry_init (JERRY_INIT_EMPTY);
176
177 jerry_register_magic_strings (magic_strings,
178 sizeof (magic_string_lengths) / sizeof (jerry_length_t),
179 magic_string_lengths);
180
181 jerry_value_t res = jerry_exec_snapshot (snapshot_p, snapshot_size, 0, exec_snapshot_flags);
182
183 TEST_ASSERT (!jerry_value_is_error (res));
184 TEST_ASSERT (jerry_value_is_string (res));
185 jerry_size_t sz = jerry_get_string_size (res);
186 TEST_ASSERT (sz == 20);
187 sz = jerry_string_to_char_buffer (res, (jerry_char_t *) string_data, sz);
188 TEST_ASSERT (sz == 20);
189 jerry_release_value (res);
190 TEST_ASSERT (!strncmp (string_data, "string from snapshot", (size_t) sz));
191
192 jerry_cleanup ();
193 } /* test_exec_snapshot */
194
195 int
main(void)196 main (void)
197 {
198 static uint32_t snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
199
200 TEST_INIT ();
201
202 /* Dump / execute snapshot */
203 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
204 && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
205 {
206 const jerry_char_t code_to_snapshot[] = "(function () { return 'string from snapshot'; }) ();";
207
208 jerry_init (JERRY_INIT_EMPTY);
209 jerry_value_t generate_result;
210 generate_result = jerry_generate_snapshot (NULL,
211 0,
212 code_to_snapshot,
213 sizeof (code_to_snapshot) - 1,
214 0,
215 snapshot_buffer,
216 SNAPSHOT_BUFFER_SIZE);
217 TEST_ASSERT (!jerry_value_is_error (generate_result)
218 && jerry_value_is_number (generate_result));
219
220 size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
221 jerry_release_value (generate_result);
222
223 /* Check the snapshot data. Unused bytes should be filled with zeroes */
224 const uint8_t expected_data[] =
225 {
226 0x4A, 0x52, 0x52, 0x59, 0x2C, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
228 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
229 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,
230 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00,
231 0x2C, 0x00, 0xC9, 0x53, 0x00, 0x00, 0x00, 0x00,
232 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00,
234 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x14, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
236 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x73, 0x6E,
237 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74,
238 };
239
240 if (sizeof (expected_data) != snapshot_size || memcmp (expected_data, snapshot_buffer, sizeof (expected_data)))
241 {
242 printf ("Snapshot data has been changed, please update tests/unit-core/test-snapshot.c.\n");
243 printf ("-------------------------------------------------------------------------------\n");
244 printf (" const uint8_t expected_data[] =\n");
245 printf (" {");
246 for (unsigned int i = 0; i < snapshot_size; i++)
247 {
248 if ((i % 8) == 0)
249 {
250 printf ("\n ");
251 }
252 printf (" 0x%02X,", ((uint8_t *) snapshot_buffer)[i]);
253 }
254 printf ("\n };\n");
255 printf ("-------------------------------------------------------------------------------\n");
256 }
257
258 TEST_ASSERT (sizeof (expected_data) == snapshot_size);
259 TEST_ASSERT (0 == memcmp (expected_data, snapshot_buffer, sizeof (expected_data)));
260
261 jerry_cleanup ();
262
263 test_exec_snapshot (snapshot_buffer, snapshot_size, 0);
264 test_exec_snapshot (snapshot_buffer, snapshot_size, JERRY_SNAPSHOT_EXEC_COPY_DATA);
265 }
266
267 /* Static snapshot */
268 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
269 && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
270 {
271 const jerry_char_t code_to_snapshot[] = TEST_STRING_LITERAL (
272 "function func(a, b, c) {"
273 " c = 'snapshot';"
274 " return arguments[0] + ' ' + b + ' ' + arguments[2];"
275 "};"
276 "func('string', 'from');"
277 );
278
279 jerry_init (JERRY_INIT_EMPTY);
280 jerry_register_magic_strings (magic_strings,
281 sizeof (magic_string_lengths) / sizeof (jerry_length_t),
282 magic_string_lengths);
283
284 jerry_value_t generate_result;
285 generate_result = jerry_generate_snapshot (NULL,
286 0,
287 code_to_snapshot,
288 sizeof (code_to_snapshot) - 1,
289 JERRY_SNAPSHOT_SAVE_STATIC,
290 snapshot_buffer,
291 SNAPSHOT_BUFFER_SIZE);
292 TEST_ASSERT (!jerry_value_is_error (generate_result)
293 && jerry_value_is_number (generate_result));
294
295 size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
296 jerry_release_value (generate_result);
297
298 /* Static snapshots are not supported by default. */
299 jerry_value_t exec_result = jerry_exec_snapshot (snapshot_buffer, snapshot_size, 0, 0);
300 TEST_ASSERT (jerry_value_is_error (exec_result));
301 jerry_release_value (exec_result);
302
303 jerry_cleanup ();
304
305 test_exec_snapshot (snapshot_buffer, snapshot_size, JERRY_SNAPSHOT_EXEC_ALLOW_STATIC);
306 }
307
308 /* Merge snapshot */
309 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
310 && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
311 {
312 static uint32_t snapshot_buffer_0[SNAPSHOT_BUFFER_SIZE];
313 static uint32_t snapshot_buffer_1[SNAPSHOT_BUFFER_SIZE];
314 size_t snapshot_sizes[2];
315 static uint32_t merged_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
316
317 const jerry_char_t code_to_snapshot1[] = "var a = 'hello'; 123";
318
319 jerry_init (JERRY_INIT_EMPTY);
320 jerry_value_t generate_result;
321 generate_result = jerry_generate_snapshot (NULL,
322 0,
323 code_to_snapshot1,
324 sizeof (code_to_snapshot1) - 1,
325 0,
326 snapshot_buffer_0,
327 SNAPSHOT_BUFFER_SIZE);
328 TEST_ASSERT (!jerry_value_is_error (generate_result)
329 && jerry_value_is_number (generate_result));
330
331 snapshot_sizes[0] = (size_t) jerry_get_number_value (generate_result);
332 jerry_release_value (generate_result);
333
334 jerry_cleanup ();
335
336 const jerry_char_t code_to_snapshot2[] = "var b = 'hello'; 456";
337
338 jerry_init (JERRY_INIT_EMPTY);
339 generate_result = jerry_generate_snapshot (NULL,
340 0,
341 code_to_snapshot2,
342 sizeof (code_to_snapshot2) - 1,
343 0,
344 snapshot_buffer_1,
345 SNAPSHOT_BUFFER_SIZE);
346 TEST_ASSERT (!jerry_value_is_error (generate_result)
347 && jerry_value_is_number (generate_result));
348
349 snapshot_sizes[1] = (size_t) jerry_get_number_value (generate_result);
350 jerry_release_value (generate_result);
351
352 jerry_cleanup ();
353
354 jerry_init (JERRY_INIT_EMPTY);
355
356 const char *error_p;
357 const uint32_t *snapshot_buffers[2];
358
359 snapshot_buffers[0] = snapshot_buffer_0;
360 snapshot_buffers[1] = snapshot_buffer_1;
361
362 static uint32_t snapshot_buffer_0_bck[SNAPSHOT_BUFFER_SIZE];
363 static uint32_t snapshot_buffer_1_bck[SNAPSHOT_BUFFER_SIZE];
364
365 memcpy (snapshot_buffer_0_bck, snapshot_buffer_0, SNAPSHOT_BUFFER_SIZE);
366 memcpy (snapshot_buffer_1_bck, snapshot_buffer_1, SNAPSHOT_BUFFER_SIZE);
367
368 size_t merged_size = jerry_merge_snapshots (snapshot_buffers,
369 snapshot_sizes,
370 2,
371 merged_snapshot_buffer,
372 SNAPSHOT_BUFFER_SIZE,
373 &error_p);
374
375 jerry_cleanup ();
376
377 TEST_ASSERT (0 == memcmp (snapshot_buffer_0_bck, snapshot_buffer_0, SNAPSHOT_BUFFER_SIZE));
378 TEST_ASSERT (0 == memcmp (snapshot_buffer_1_bck, snapshot_buffer_1, SNAPSHOT_BUFFER_SIZE));
379
380 jerry_init (JERRY_INIT_EMPTY);
381
382 jerry_value_t res = jerry_exec_snapshot (merged_snapshot_buffer, merged_size, 0, 0);
383 TEST_ASSERT (!jerry_value_is_error (res));
384 TEST_ASSERT (jerry_get_number_value (res) == 123);
385 jerry_release_value (res);
386
387 res = jerry_exec_snapshot (merged_snapshot_buffer, merged_size, 1, 0);
388 TEST_ASSERT (!jerry_value_is_error (res));
389 TEST_ASSERT (jerry_get_number_value (res) == 456);
390 jerry_release_value (res);
391
392 jerry_cleanup ();
393 }
394
395 /* Save literals */
396 if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE))
397 {
398 /* C format generation */
399 jerry_init (JERRY_INIT_EMPTY);
400
401 static jerry_char_t literal_buffer_c[LITERAL_BUFFER_SIZE];
402 static uint32_t literal_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
403 static const jerry_char_t code_for_c_format[] = "var object = { aa:'fo\" o\\n \\\\', Bb:'max', aaa:'xzy0' };";
404
405 jerry_value_t generate_result;
406 generate_result = jerry_generate_snapshot (NULL,
407 0,
408 code_for_c_format,
409 sizeof (code_for_c_format) - 1,
410 0,
411 literal_snapshot_buffer,
412 SNAPSHOT_BUFFER_SIZE);
413
414 TEST_ASSERT (!jerry_value_is_error (generate_result));
415 TEST_ASSERT (jerry_value_is_number (generate_result));
416
417 size_t snapshot_size = (size_t) jerry_get_number_value (generate_result);
418 jerry_release_value (generate_result);
419
420 /* In ES2015 we emit extra bytecode instructions to check global variable redeclaration. */
421 const size_t expected_size = (jerry_is_feature_enabled (JERRY_FEATURE_SYMBOL)) ? 132 : 124;
422 TEST_ASSERT (snapshot_size == expected_size);
423
424 const size_t lit_c_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer,
425 snapshot_size,
426 literal_buffer_c,
427 LITERAL_BUFFER_SIZE,
428 true);
429 TEST_ASSERT (lit_c_buf_sz == 239);
430
431 static const char *expected_c_format = (
432 "jerry_length_t literal_count = 5;\n\n"
433 "jerry_char_t *literals[5] =\n"
434 "{\n"
435 " \"Bb\",\n"
436 " \"aa\",\n"
437 " \"aaa\",\n"
438 " \"xzy0\",\n"
439 " \"fo\\\" o\\x0A \\\\\"\n"
440 "};\n\n"
441 "jerry_length_t literal_sizes[5] =\n"
442 "{\n"
443 " 2 /* Bb */,\n"
444 " 2 /* aa */,\n"
445 " 3 /* aaa */,\n"
446 " 4 /* xzy0 */,\n"
447 " 8 /* fo\" o\n \\ */\n"
448 "};\n"
449 );
450
451 TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, lit_c_buf_sz));
452
453 /* List format generation */
454 static jerry_char_t literal_buffer_list[LITERAL_BUFFER_SIZE];
455 const size_t lit_list_buf_sz = jerry_get_literals_from_snapshot (literal_snapshot_buffer,
456 snapshot_size,
457 literal_buffer_list,
458 LITERAL_BUFFER_SIZE,
459 false);
460 TEST_ASSERT (lit_list_buf_sz == 34);
461 TEST_ASSERT (!strncmp ((char *) literal_buffer_list,
462 "2 Bb\n2 aa\n3 aaa\n4 xzy0\n8 fo\" o\n \\\n",
463 lit_list_buf_sz));
464
465 jerry_cleanup ();
466 }
467
468 test_function_snapshot ();
469
470 test_function_arguments_snapshot ();
471
472 return 0;
473 } /* main */
474