1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci#include "ecma-conversion.h"
17425bb815Sopenharmony_ci#include "ecma-exceptions.h"
18425bb815Sopenharmony_ci#include "ecma-function-object.h"
19425bb815Sopenharmony_ci#include "ecma-helpers.h"
20425bb815Sopenharmony_ci#include "ecma-lex-env.h"
21425bb815Sopenharmony_ci#include "ecma-literal-storage.h"
22425bb815Sopenharmony_ci#include "jcontext.h"
23425bb815Sopenharmony_ci#include "jerryscript.h"
24425bb815Sopenharmony_ci#include "jerry-snapshot.h"
25425bb815Sopenharmony_ci#include "js-parser.h"
26425bb815Sopenharmony_ci#include "lit-char-helpers.h"
27425bb815Sopenharmony_ci#include "re-compiler.h"
28425bb815Sopenharmony_ci
29425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE) || ENABLED (JERRY_SNAPSHOT_EXEC)
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/**
32425bb815Sopenharmony_ci * Get snapshot configuration flags.
33425bb815Sopenharmony_ci *
34425bb815Sopenharmony_ci * @return configuration flags
35425bb815Sopenharmony_ci */
36425bb815Sopenharmony_cistatic inline uint32_t JERRY_ATTR_ALWAYS_INLINE
37425bb815Sopenharmony_cisnapshot_get_global_flags (bool has_regex, /**< regex literal is present */
38425bb815Sopenharmony_ci                           bool has_class) /**< class literal is present */
39425bb815Sopenharmony_ci{
40425bb815Sopenharmony_ci  JERRY_UNUSED (has_regex);
41425bb815Sopenharmony_ci  JERRY_UNUSED (has_class);
42425bb815Sopenharmony_ci
43425bb815Sopenharmony_ci  uint32_t flags = 0;
44425bb815Sopenharmony_ci
45425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_REGEXP)
46425bb815Sopenharmony_ci  flags |= (has_regex ? JERRY_SNAPSHOT_HAS_REGEX_LITERAL : 0);
47425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
48425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
49425bb815Sopenharmony_ci  flags |= (has_class ? JERRY_SNAPSHOT_HAS_CLASS_LITERAL : 0);
50425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
51425bb815Sopenharmony_ci
52425bb815Sopenharmony_ci  return flags;
53425bb815Sopenharmony_ci} /* snapshot_get_global_flags */
54425bb815Sopenharmony_ci
55425bb815Sopenharmony_ci/**
56425bb815Sopenharmony_ci * Checks whether the global_flags argument matches to the current feature set.
57425bb815Sopenharmony_ci *
58425bb815Sopenharmony_ci * @return true if global_flags accepted, false otherwise
59425bb815Sopenharmony_ci */
60425bb815Sopenharmony_cistatic inline bool JERRY_ATTR_ALWAYS_INLINE
61425bb815Sopenharmony_cisnapshot_check_global_flags (uint32_t global_flags) /**< global flags */
62425bb815Sopenharmony_ci{
63425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_REGEXP)
64425bb815Sopenharmony_ci  global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_REGEX_LITERAL;
65425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
66425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
67425bb815Sopenharmony_ci  global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_CLASS_LITERAL;
68425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
69425bb815Sopenharmony_ci
70425bb815Sopenharmony_ci  return global_flags == snapshot_get_global_flags (false, false);
71425bb815Sopenharmony_ci} /* snapshot_check_global_flags */
72425bb815Sopenharmony_ci
73425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) || ENABLED (JERRY_SNAPSHOT_EXEC) */
74425bb815Sopenharmony_ci
75425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
76425bb815Sopenharmony_ci
77425bb815Sopenharmony_ci/**
78425bb815Sopenharmony_ci * Variables required to take a snapshot.
79425bb815Sopenharmony_ci */
80425bb815Sopenharmony_citypedef struct
81425bb815Sopenharmony_ci{
82425bb815Sopenharmony_ci  size_t snapshot_buffer_write_offset;
83425bb815Sopenharmony_ci  ecma_value_t snapshot_error;
84425bb815Sopenharmony_ci  bool regex_found;
85425bb815Sopenharmony_ci  bool class_found;
86425bb815Sopenharmony_ci} snapshot_globals_t;
87425bb815Sopenharmony_ci
88425bb815Sopenharmony_ci/** \addtogroup jerrysnapshot Jerry snapshot operations
89425bb815Sopenharmony_ci * @{
90425bb815Sopenharmony_ci */
91425bb815Sopenharmony_ci
92425bb815Sopenharmony_ci/**
93425bb815Sopenharmony_ci * Write data into the specified buffer.
94425bb815Sopenharmony_ci *
95425bb815Sopenharmony_ci * Note:
96425bb815Sopenharmony_ci *      Offset is in-out and is incremented if the write operation completes successfully.
97425bb815Sopenharmony_ci *
98425bb815Sopenharmony_ci * @return true - if write was successful, i.e. offset + data_size doesn't exceed buffer size,
99425bb815Sopenharmony_ci *         false - otherwise
100425bb815Sopenharmony_ci */
101425bb815Sopenharmony_cistatic inline bool JERRY_ATTR_ALWAYS_INLINE
102425bb815Sopenharmony_cisnapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */
103425bb815Sopenharmony_ci                                    size_t buffer_size, /**< size of buffer */
104425bb815Sopenharmony_ci                                    size_t *in_out_buffer_offset_p,  /**< [in,out] offset to write to
105425bb815Sopenharmony_ci                                                                      * incremented with data_size */
106425bb815Sopenharmony_ci                                    const void *data_p, /**< data */
107425bb815Sopenharmony_ci                                    size_t data_size) /**< size of the writable data */
108425bb815Sopenharmony_ci{
109425bb815Sopenharmony_ci  if (*in_out_buffer_offset_p + data_size > buffer_size)
110425bb815Sopenharmony_ci  {
111425bb815Sopenharmony_ci    return false;
112425bb815Sopenharmony_ci  }
113425bb815Sopenharmony_ci
114425bb815Sopenharmony_ci  memcpy (buffer_p + *in_out_buffer_offset_p, data_p, data_size);
115425bb815Sopenharmony_ci  *in_out_buffer_offset_p += data_size;
116425bb815Sopenharmony_ci
117425bb815Sopenharmony_ci  return true;
118425bb815Sopenharmony_ci} /* snapshot_write_to_buffer_by_offset */
119425bb815Sopenharmony_ci
120425bb815Sopenharmony_ci/**
121425bb815Sopenharmony_ci * Maximum snapshot write buffer offset.
122425bb815Sopenharmony_ci */
123425bb815Sopenharmony_ci#if !ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
124425bb815Sopenharmony_ci#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (0x7fffff >> 1)
125425bb815Sopenharmony_ci#else /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
126425bb815Sopenharmony_ci#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (UINT32_MAX >> 1)
127425bb815Sopenharmony_ci#endif /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
128425bb815Sopenharmony_ci
129425bb815Sopenharmony_ci/**
130425bb815Sopenharmony_ci * Save snapshot helper.
131425bb815Sopenharmony_ci *
132425bb815Sopenharmony_ci * @return start offset
133425bb815Sopenharmony_ci */
134425bb815Sopenharmony_cistatic uint32_t
135425bb815Sopenharmony_cisnapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */
136425bb815Sopenharmony_ci                            uint8_t *snapshot_buffer_p, /**< snapshot buffer */
137425bb815Sopenharmony_ci                            size_t snapshot_buffer_size, /**< snapshot buffer size */
138425bb815Sopenharmony_ci                            snapshot_globals_t *globals_p) /**< snapshot globals */
139425bb815Sopenharmony_ci{
140425bb815Sopenharmony_ci  const jerry_char_t *error_buffer_too_small_p = (const jerry_char_t *) "Snapshot buffer too small.";
141425bb815Sopenharmony_ci
142425bb815Sopenharmony_ci  if (!ecma_is_value_empty (globals_p->snapshot_error))
143425bb815Sopenharmony_ci  {
144425bb815Sopenharmony_ci    return 0;
145425bb815Sopenharmony_ci  }
146425bb815Sopenharmony_ci
147425bb815Sopenharmony_ci  JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0);
148425bb815Sopenharmony_ci
149425bb815Sopenharmony_ci  if (globals_p->snapshot_buffer_write_offset > JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
150425bb815Sopenharmony_ci  {
151425bb815Sopenharmony_ci    const char * const error_message_p = "Maximum snapshot size reached.";
152425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
153425bb815Sopenharmony_ci    return 0;
154425bb815Sopenharmony_ci  }
155425bb815Sopenharmony_ci
156425bb815Sopenharmony_ci  /* The snapshot generator always parses a single file,
157425bb815Sopenharmony_ci   * so the base always starts right after the snapshot header. */
158425bb815Sopenharmony_ci  uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t));
159425bb815Sopenharmony_ci
160425bb815Sopenharmony_ci  uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset;
161425bb815Sopenharmony_ci  ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p;
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
164425bb815Sopenharmony_ci  if (compiled_code_p->status_flags & CBC_CODE_FLAG_HAS_TAGGED_LITERALS)
165425bb815Sopenharmony_ci  {
166425bb815Sopenharmony_ci    const char * const error_message_p = "Unsupported feature: tagged template literals.";
167425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
168425bb815Sopenharmony_ci    return 0;
169425bb815Sopenharmony_ci  }
170425bb815Sopenharmony_ci
171425bb815Sopenharmony_ci  if (compiled_code_p->status_flags & CBC_CODE_FLAGS_CLASS_CONSTRUCTOR)
172425bb815Sopenharmony_ci  {
173425bb815Sopenharmony_ci    globals_p->class_found = true;
174425bb815Sopenharmony_ci  }
175425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
176425bb815Sopenharmony_ci
177425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_REGEXP)
178425bb815Sopenharmony_ci  if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
179425bb815Sopenharmony_ci  {
180425bb815Sopenharmony_ci    /* Regular expression. */
181425bb815Sopenharmony_ci    if (globals_p->snapshot_buffer_write_offset + sizeof (ecma_compiled_code_t) > snapshot_buffer_size)
182425bb815Sopenharmony_ci    {
183425bb815Sopenharmony_ci      globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
184425bb815Sopenharmony_ci      return 0;
185425bb815Sopenharmony_ci    }
186425bb815Sopenharmony_ci
187425bb815Sopenharmony_ci    globals_p->snapshot_buffer_write_offset += sizeof (ecma_compiled_code_t);
188425bb815Sopenharmony_ci
189425bb815Sopenharmony_ci    ecma_value_t pattern = ((re_compiled_code_t *) compiled_code_p)->source;
190425bb815Sopenharmony_ci    ecma_string_t *pattern_string_p = ecma_get_string_from_value (pattern);
191425bb815Sopenharmony_ci
192425bb815Sopenharmony_ci    ecma_length_t pattern_size = 0;
193425bb815Sopenharmony_ci
194425bb815Sopenharmony_ci    ECMA_STRING_TO_UTF8_STRING (pattern_string_p, buffer_p, buffer_size);
195425bb815Sopenharmony_ci
196425bb815Sopenharmony_ci    pattern_size = buffer_size;
197425bb815Sopenharmony_ci
198425bb815Sopenharmony_ci    if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
199425bb815Sopenharmony_ci                                             snapshot_buffer_size,
200425bb815Sopenharmony_ci                                             &globals_p->snapshot_buffer_write_offset,
201425bb815Sopenharmony_ci                                             buffer_p,
202425bb815Sopenharmony_ci                                             buffer_size))
203425bb815Sopenharmony_ci    {
204425bb815Sopenharmony_ci      globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
205425bb815Sopenharmony_ci      /* cannot return inside ECMA_FINALIZE_UTF8_STRING */
206425bb815Sopenharmony_ci    }
207425bb815Sopenharmony_ci
208425bb815Sopenharmony_ci    ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);
209425bb815Sopenharmony_ci
210425bb815Sopenharmony_ci    if (!ecma_is_value_empty (globals_p->snapshot_error))
211425bb815Sopenharmony_ci    {
212425bb815Sopenharmony_ci      return 0;
213425bb815Sopenharmony_ci    }
214425bb815Sopenharmony_ci
215425bb815Sopenharmony_ci    globals_p->regex_found = true;
216425bb815Sopenharmony_ci    globals_p->snapshot_buffer_write_offset = JERRY_ALIGNUP (globals_p->snapshot_buffer_write_offset,
217425bb815Sopenharmony_ci                                                             JMEM_ALIGNMENT);
218425bb815Sopenharmony_ci
219425bb815Sopenharmony_ci    /* Regexp character size is stored in refs. */
220425bb815Sopenharmony_ci    copied_code_p->refs = (uint16_t) pattern_size;
221425bb815Sopenharmony_ci
222425bb815Sopenharmony_ci    pattern_size += (ecma_length_t) sizeof (ecma_compiled_code_t);
223425bb815Sopenharmony_ci    copied_code_p->size = (uint16_t) ((pattern_size + JMEM_ALIGNMENT - 1) >> JMEM_ALIGNMENT_LOG);
224425bb815Sopenharmony_ci
225425bb815Sopenharmony_ci    copied_code_p->status_flags = compiled_code_p->status_flags;
226425bb815Sopenharmony_ci
227425bb815Sopenharmony_ci    return start_offset;
228425bb815Sopenharmony_ci  }
229425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
230425bb815Sopenharmony_ci
231425bb815Sopenharmony_ci  JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
232425bb815Sopenharmony_ci
233425bb815Sopenharmony_ci  if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
234425bb815Sopenharmony_ci                                           snapshot_buffer_size,
235425bb815Sopenharmony_ci                                           &globals_p->snapshot_buffer_write_offset,
236425bb815Sopenharmony_ci                                           compiled_code_p,
237425bb815Sopenharmony_ci                                           ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG))
238425bb815Sopenharmony_ci  {
239425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
240425bb815Sopenharmony_ci    return 0;
241425bb815Sopenharmony_ci  }
242425bb815Sopenharmony_ci
243425bb815Sopenharmony_ci  /* Sub-functions and regular expressions are stored recursively. */
244425bb815Sopenharmony_ci  uint8_t *buffer_p = (uint8_t *) copied_code_p;
245425bb815Sopenharmony_ci  ecma_value_t *literal_start_p;
246425bb815Sopenharmony_ci  uint32_t const_literal_end;
247425bb815Sopenharmony_ci  uint32_t literal_end;
248425bb815Sopenharmony_ci
249425bb815Sopenharmony_ci  if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
250425bb815Sopenharmony_ci  {
251425bb815Sopenharmony_ci    literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
252425bb815Sopenharmony_ci
253425bb815Sopenharmony_ci    cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
254425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
255425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
256425bb815Sopenharmony_ci  }
257425bb815Sopenharmony_ci  else
258425bb815Sopenharmony_ci  {
259425bb815Sopenharmony_ci    literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
260425bb815Sopenharmony_ci
261425bb815Sopenharmony_ci    cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
262425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
263425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
264425bb815Sopenharmony_ci  }
265425bb815Sopenharmony_ci
266425bb815Sopenharmony_ci  for (uint32_t i = const_literal_end; i < literal_end; i++)
267425bb815Sopenharmony_ci  {
268425bb815Sopenharmony_ci    ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
269425bb815Sopenharmony_ci                                                                        literal_start_p[i]);
270425bb815Sopenharmony_ci
271425bb815Sopenharmony_ci    if (bytecode_p == compiled_code_p)
272425bb815Sopenharmony_ci    {
273425bb815Sopenharmony_ci      literal_start_p[i] = 0;
274425bb815Sopenharmony_ci    }
275425bb815Sopenharmony_ci    else
276425bb815Sopenharmony_ci    {
277425bb815Sopenharmony_ci      uint32_t offset = snapshot_add_compiled_code (bytecode_p,
278425bb815Sopenharmony_ci                                                    snapshot_buffer_p,
279425bb815Sopenharmony_ci                                                    snapshot_buffer_size,
280425bb815Sopenharmony_ci                                                    globals_p);
281425bb815Sopenharmony_ci
282425bb815Sopenharmony_ci      JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset);
283425bb815Sopenharmony_ci
284425bb815Sopenharmony_ci      literal_start_p[i] = offset - start_offset;
285425bb815Sopenharmony_ci    }
286425bb815Sopenharmony_ci  }
287425bb815Sopenharmony_ci
288425bb815Sopenharmony_ci  return start_offset;
289425bb815Sopenharmony_ci} /* snapshot_add_compiled_code */
290425bb815Sopenharmony_ci
291425bb815Sopenharmony_ci/**
292425bb815Sopenharmony_ci * Create unsupported literal error.
293425bb815Sopenharmony_ci */
294425bb815Sopenharmony_cistatic void
295425bb815Sopenharmony_cistatic_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< snapshot globals */
296425bb815Sopenharmony_ci                                           ecma_value_t literal) /**< literal form the literal pool */
297425bb815Sopenharmony_ci{
298425bb815Sopenharmony_ci  lit_utf8_byte_t *str_p = (lit_utf8_byte_t *) "Unsupported static snapshot literal: ";
299425bb815Sopenharmony_ci  ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw (str_p, 37);
300425bb815Sopenharmony_ci
301425bb815Sopenharmony_ci  JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (literal));
302425bb815Sopenharmony_ci
303425bb815Sopenharmony_ci  ecma_string_t *literal_string_p = ecma_op_to_string (literal);
304425bb815Sopenharmony_ci  JERRY_ASSERT (literal_string_p != NULL);
305425bb815Sopenharmony_ci
306425bb815Sopenharmony_ci  ecma_stringbuilder_append (&builder, literal_string_p);
307425bb815Sopenharmony_ci
308425bb815Sopenharmony_ci  ecma_deref_ecma_string (literal_string_p);
309425bb815Sopenharmony_ci
310425bb815Sopenharmony_ci  ecma_object_t *error_object_p = ecma_new_standard_error_with_message (ECMA_ERROR_RANGE,
311425bb815Sopenharmony_ci                                                                        ecma_stringbuilder_finalize (&builder));
312425bb815Sopenharmony_ci
313425bb815Sopenharmony_ci  globals_p->snapshot_error = ecma_create_error_object_reference (error_object_p);
314425bb815Sopenharmony_ci} /* static_snapshot_error_unsupported_literal */
315425bb815Sopenharmony_ci
316425bb815Sopenharmony_ci/**
317425bb815Sopenharmony_ci * Save static snapshot helper.
318425bb815Sopenharmony_ci *
319425bb815Sopenharmony_ci * @return start offset
320425bb815Sopenharmony_ci */
321425bb815Sopenharmony_cistatic uint32_t
322425bb815Sopenharmony_cistatic_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */
323425bb815Sopenharmony_ci                                   uint8_t *snapshot_buffer_p, /**< snapshot buffer */
324425bb815Sopenharmony_ci                                   size_t snapshot_buffer_size, /**< snapshot buffer size */
325425bb815Sopenharmony_ci                                   snapshot_globals_t *globals_p) /**< snapshot globals */
326425bb815Sopenharmony_ci{
327425bb815Sopenharmony_ci  if (!ecma_is_value_empty (globals_p->snapshot_error))
328425bb815Sopenharmony_ci  {
329425bb815Sopenharmony_ci    return 0;
330425bb815Sopenharmony_ci  }
331425bb815Sopenharmony_ci
332425bb815Sopenharmony_ci  JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0);
333425bb815Sopenharmony_ci
334425bb815Sopenharmony_ci  if (globals_p->snapshot_buffer_write_offset >= JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
335425bb815Sopenharmony_ci  {
336425bb815Sopenharmony_ci    const char * const error_message_p = "Maximum snapshot size reached.";
337425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
338425bb815Sopenharmony_ci    return 0;
339425bb815Sopenharmony_ci  }
340425bb815Sopenharmony_ci
341425bb815Sopenharmony_ci  /* The snapshot generator always parses a single file,
342425bb815Sopenharmony_ci   * so the base always starts right after the snapshot header. */
343425bb815Sopenharmony_ci  uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t));
344425bb815Sopenharmony_ci
345425bb815Sopenharmony_ci  uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset;
346425bb815Sopenharmony_ci  ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p;
347425bb815Sopenharmony_ci
348425bb815Sopenharmony_ci  if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
349425bb815Sopenharmony_ci  {
350425bb815Sopenharmony_ci    /* Regular expression literals are not supported. */
351425bb815Sopenharmony_ci    const char * const error_message_p = "Regular expression literals are not supported.";
352425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
353425bb815Sopenharmony_ci    return 0;
354425bb815Sopenharmony_ci  }
355425bb815Sopenharmony_ci
356425bb815Sopenharmony_ci  if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
357425bb815Sopenharmony_ci                                           snapshot_buffer_size,
358425bb815Sopenharmony_ci                                           &globals_p->snapshot_buffer_write_offset,
359425bb815Sopenharmony_ci                                           compiled_code_p,
360425bb815Sopenharmony_ci                                           ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG))
361425bb815Sopenharmony_ci  {
362425bb815Sopenharmony_ci    const char * const error_message_p = "Snapshot buffer too small.";
363425bb815Sopenharmony_ci    globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
364425bb815Sopenharmony_ci    return 0;
365425bb815Sopenharmony_ci  }
366425bb815Sopenharmony_ci
367425bb815Sopenharmony_ci  /* Sub-functions and regular expressions are stored recursively. */
368425bb815Sopenharmony_ci  uint8_t *buffer_p = (uint8_t *) copied_code_p;
369425bb815Sopenharmony_ci  ecma_value_t *literal_start_p;
370425bb815Sopenharmony_ci  uint32_t argument_end;
371425bb815Sopenharmony_ci  uint32_t const_literal_end;
372425bb815Sopenharmony_ci  uint32_t literal_end;
373425bb815Sopenharmony_ci
374425bb815Sopenharmony_ci  ((ecma_compiled_code_t *) copied_code_p)->status_flags |= CBC_CODE_FLAGS_STATIC_FUNCTION;
375425bb815Sopenharmony_ci
376425bb815Sopenharmony_ci  if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
377425bb815Sopenharmony_ci  {
378425bb815Sopenharmony_ci    literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
379425bb815Sopenharmony_ci
380425bb815Sopenharmony_ci    cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
381425bb815Sopenharmony_ci    argument_end = args_p->argument_end;
382425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
383425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
384425bb815Sopenharmony_ci  }
385425bb815Sopenharmony_ci  else
386425bb815Sopenharmony_ci  {
387425bb815Sopenharmony_ci    literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
388425bb815Sopenharmony_ci
389425bb815Sopenharmony_ci    cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
390425bb815Sopenharmony_ci    argument_end = args_p->argument_end;
391425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
392425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
393425bb815Sopenharmony_ci  }
394425bb815Sopenharmony_ci
395425bb815Sopenharmony_ci  for (uint32_t i = 0; i < const_literal_end; i++)
396425bb815Sopenharmony_ci  {
397425bb815Sopenharmony_ci    if (!ecma_is_value_direct (literal_start_p[i])
398425bb815Sopenharmony_ci        && !ecma_is_value_direct_string (literal_start_p[i]))
399425bb815Sopenharmony_ci    {
400425bb815Sopenharmony_ci      static_snapshot_error_unsupported_literal (globals_p, literal_start_p[i]);
401425bb815Sopenharmony_ci      return 0;
402425bb815Sopenharmony_ci    }
403425bb815Sopenharmony_ci  }
404425bb815Sopenharmony_ci
405425bb815Sopenharmony_ci  for (uint32_t i = const_literal_end; i < literal_end; i++)
406425bb815Sopenharmony_ci  {
407425bb815Sopenharmony_ci    ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
408425bb815Sopenharmony_ci                                                                        literal_start_p[i]);
409425bb815Sopenharmony_ci
410425bb815Sopenharmony_ci    if (bytecode_p == compiled_code_p)
411425bb815Sopenharmony_ci    {
412425bb815Sopenharmony_ci      literal_start_p[i] = 0;
413425bb815Sopenharmony_ci    }
414425bb815Sopenharmony_ci    else
415425bb815Sopenharmony_ci    {
416425bb815Sopenharmony_ci      uint32_t offset = static_snapshot_add_compiled_code (bytecode_p,
417425bb815Sopenharmony_ci                                                           snapshot_buffer_p,
418425bb815Sopenharmony_ci                                                           snapshot_buffer_size,
419425bb815Sopenharmony_ci                                                           globals_p);
420425bb815Sopenharmony_ci
421425bb815Sopenharmony_ci      JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset);
422425bb815Sopenharmony_ci
423425bb815Sopenharmony_ci      literal_start_p[i] = offset - start_offset;
424425bb815Sopenharmony_ci    }
425425bb815Sopenharmony_ci  }
426425bb815Sopenharmony_ci
427425bb815Sopenharmony_ci  if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
428425bb815Sopenharmony_ci  {
429425bb815Sopenharmony_ci    buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG;
430425bb815Sopenharmony_ci    literal_start_p = ((ecma_value_t *) buffer_p) - argument_end;
431425bb815Sopenharmony_ci
432425bb815Sopenharmony_ci    for (uint32_t i = 0; i < argument_end; i++)
433425bb815Sopenharmony_ci    {
434425bb815Sopenharmony_ci      if (!ecma_is_value_direct_string (literal_start_p[i]))
435425bb815Sopenharmony_ci      {
436425bb815Sopenharmony_ci        static_snapshot_error_unsupported_literal (globals_p, literal_start_p[i]);
437425bb815Sopenharmony_ci        return 0;
438425bb815Sopenharmony_ci      }
439425bb815Sopenharmony_ci    }
440425bb815Sopenharmony_ci  }
441425bb815Sopenharmony_ci
442425bb815Sopenharmony_ci  return start_offset;
443425bb815Sopenharmony_ci} /* static_snapshot_add_compiled_code */
444425bb815Sopenharmony_ci
445425bb815Sopenharmony_ci/**
446425bb815Sopenharmony_ci * Set the uint16_t offsets in the code area.
447425bb815Sopenharmony_ci */
448425bb815Sopenharmony_cistatic void
449425bb815Sopenharmony_cijerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
450425bb815Sopenharmony_ci                            uint32_t size, /**< buffer size */
451425bb815Sopenharmony_ci                            lit_mem_to_snapshot_id_map_entry_t *lit_map_p) /**< literal map */
452425bb815Sopenharmony_ci{
453425bb815Sopenharmony_ci  JERRY_ASSERT (size > 0);
454425bb815Sopenharmony_ci
455425bb815Sopenharmony_ci  do
456425bb815Sopenharmony_ci  {
457425bb815Sopenharmony_ci    ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
458425bb815Sopenharmony_ci    uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
459425bb815Sopenharmony_ci
460425bb815Sopenharmony_ci    if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
461425bb815Sopenharmony_ci    {
462425bb815Sopenharmony_ci      ecma_value_t *literal_start_p;
463425bb815Sopenharmony_ci      uint32_t argument_end;
464425bb815Sopenharmony_ci      uint32_t const_literal_end;
465425bb815Sopenharmony_ci
466425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
467425bb815Sopenharmony_ci      {
468425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint16_arguments_t));
469425bb815Sopenharmony_ci
470425bb815Sopenharmony_ci        cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
471425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
472425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
473425bb815Sopenharmony_ci      }
474425bb815Sopenharmony_ci      else
475425bb815Sopenharmony_ci      {
476425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint8_arguments_t));
477425bb815Sopenharmony_ci
478425bb815Sopenharmony_ci        cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
479425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
480425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
481425bb815Sopenharmony_ci      }
482425bb815Sopenharmony_ci
483425bb815Sopenharmony_ci      for (uint32_t i = 0; i < const_literal_end; i++)
484425bb815Sopenharmony_ci      {
485425bb815Sopenharmony_ci        if (ecma_is_value_string (literal_start_p[i])
486425bb815Sopenharmony_ci            || ecma_is_value_float_number (literal_start_p[i]))
487425bb815Sopenharmony_ci        {
488425bb815Sopenharmony_ci          lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
489425bb815Sopenharmony_ci
490425bb815Sopenharmony_ci          while (current_p->literal_id != literal_start_p[i])
491425bb815Sopenharmony_ci          {
492425bb815Sopenharmony_ci            current_p++;
493425bb815Sopenharmony_ci          }
494425bb815Sopenharmony_ci
495425bb815Sopenharmony_ci          literal_start_p[i] = current_p->literal_offset;
496425bb815Sopenharmony_ci        }
497425bb815Sopenharmony_ci      }
498425bb815Sopenharmony_ci
499425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
500425bb815Sopenharmony_ci      {
501425bb815Sopenharmony_ci        uint8_t *byte_p = (uint8_t *) bytecode_p;
502425bb815Sopenharmony_ci        byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
503425bb815Sopenharmony_ci        literal_start_p = ((ecma_value_t *) byte_p) - argument_end;
504425bb815Sopenharmony_ci
505425bb815Sopenharmony_ci        for (uint32_t i = 0; i < argument_end; i++)
506425bb815Sopenharmony_ci        {
507425bb815Sopenharmony_ci          if (literal_start_p[i] != ECMA_VALUE_EMPTY)
508425bb815Sopenharmony_ci          {
509425bb815Sopenharmony_ci            JERRY_ASSERT (ecma_is_value_string (literal_start_p[i]));
510425bb815Sopenharmony_ci
511425bb815Sopenharmony_ci            lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
512425bb815Sopenharmony_ci
513425bb815Sopenharmony_ci            while (current_p->literal_id != literal_start_p[i])
514425bb815Sopenharmony_ci            {
515425bb815Sopenharmony_ci              current_p++;
516425bb815Sopenharmony_ci            }
517425bb815Sopenharmony_ci
518425bb815Sopenharmony_ci            literal_start_p[i] = current_p->literal_offset;
519425bb815Sopenharmony_ci          }
520425bb815Sopenharmony_ci        }
521425bb815Sopenharmony_ci      }
522425bb815Sopenharmony_ci
523425bb815Sopenharmony_ci      /* Set reference counter to 1. */
524425bb815Sopenharmony_ci      bytecode_p->refs = 1;
525425bb815Sopenharmony_ci    }
526425bb815Sopenharmony_ci
527425bb815Sopenharmony_ci    JERRY_ASSERT ((code_size % sizeof (uint32_t)) == 0);
528425bb815Sopenharmony_ci    buffer_p += code_size / sizeof (uint32_t);
529425bb815Sopenharmony_ci    size -= code_size;
530425bb815Sopenharmony_ci  }
531425bb815Sopenharmony_ci  while (size > 0);
532425bb815Sopenharmony_ci} /* jerry_snapshot_set_offsets */
533425bb815Sopenharmony_ci
534425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
535425bb815Sopenharmony_ci
536425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_EXEC)
537425bb815Sopenharmony_ci
538425bb815Sopenharmony_ci/**
539425bb815Sopenharmony_ci * Byte code blocks shorter than this threshold are always copied into the memory.
540425bb815Sopenharmony_ci * The memory / performance trade-of of byte code redirection does not worth
541425bb815Sopenharmony_ci * in such cases.
542425bb815Sopenharmony_ci */
543425bb815Sopenharmony_ci#define BYTECODE_NO_COPY_THRESHOLD 8
544425bb815Sopenharmony_ci
545425bb815Sopenharmony_ci/**
546425bb815Sopenharmony_ci * Load byte code from snapshot.
547425bb815Sopenharmony_ci *
548425bb815Sopenharmony_ci * @return byte code
549425bb815Sopenharmony_ci */
550425bb815Sopenharmony_cistatic ecma_compiled_code_t *
551425bb815Sopenharmony_cisnapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the
552425bb815Sopenharmony_ci                                                          *   current primary function */
553425bb815Sopenharmony_ci                             const uint8_t *literal_base_p, /**< literal start */
554425bb815Sopenharmony_ci                             bool copy_bytecode) /**< byte code should be copied to memory */
555425bb815Sopenharmony_ci{
556425bb815Sopenharmony_ci  ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) base_addr_p;
557425bb815Sopenharmony_ci  uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
558425bb815Sopenharmony_ci
559425bb815Sopenharmony_ci#if ENABLED (JERRY_BUILTIN_REGEXP)
560425bb815Sopenharmony_ci  if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
561425bb815Sopenharmony_ci  {
562425bb815Sopenharmony_ci
563425bb815Sopenharmony_ci    const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (ecma_compiled_code_t);
564425bb815Sopenharmony_ci
565425bb815Sopenharmony_ci    /* Real size is stored in refs. */
566425bb815Sopenharmony_ci    ecma_string_t *pattern_str_p = ecma_new_ecma_string_from_utf8 (regex_start_p,
567425bb815Sopenharmony_ci                                                                   bytecode_p->refs);
568425bb815Sopenharmony_ci
569425bb815Sopenharmony_ci    const re_compiled_code_t *re_bytecode_p = re_compile_bytecode (pattern_str_p,
570425bb815Sopenharmony_ci                                                                   bytecode_p->status_flags);
571425bb815Sopenharmony_ci    ecma_deref_ecma_string (pattern_str_p);
572425bb815Sopenharmony_ci
573425bb815Sopenharmony_ci    return (ecma_compiled_code_t *) re_bytecode_p;
574425bb815Sopenharmony_ci  }
575425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
576425bb815Sopenharmony_ci
577425bb815Sopenharmony_ci  JERRY_ASSERT (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
578425bb815Sopenharmony_ci
579425bb815Sopenharmony_ci  size_t header_size;
580425bb815Sopenharmony_ci  uint32_t argument_end = 0;
581425bb815Sopenharmony_ci  uint32_t const_literal_end;
582425bb815Sopenharmony_ci  uint32_t literal_end;
583425bb815Sopenharmony_ci
584425bb815Sopenharmony_ci  if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
585425bb815Sopenharmony_ci  {
586425bb815Sopenharmony_ci    uint8_t *byte_p = (uint8_t *) bytecode_p;
587425bb815Sopenharmony_ci    cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p;
588425bb815Sopenharmony_ci
589425bb815Sopenharmony_ci    if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
590425bb815Sopenharmony_ci    {
591425bb815Sopenharmony_ci      argument_end = args_p->argument_end;
592425bb815Sopenharmony_ci    }
593425bb815Sopenharmony_ci
594425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
595425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
596425bb815Sopenharmony_ci    header_size = sizeof (cbc_uint16_arguments_t);
597425bb815Sopenharmony_ci  }
598425bb815Sopenharmony_ci  else
599425bb815Sopenharmony_ci  {
600425bb815Sopenharmony_ci    uint8_t *byte_p = (uint8_t *) bytecode_p;
601425bb815Sopenharmony_ci    cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p;
602425bb815Sopenharmony_ci
603425bb815Sopenharmony_ci    if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
604425bb815Sopenharmony_ci    {
605425bb815Sopenharmony_ci      argument_end = args_p->argument_end;
606425bb815Sopenharmony_ci    }
607425bb815Sopenharmony_ci
608425bb815Sopenharmony_ci    const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
609425bb815Sopenharmony_ci    literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
610425bb815Sopenharmony_ci    header_size = sizeof (cbc_uint8_arguments_t);
611425bb815Sopenharmony_ci  }
612425bb815Sopenharmony_ci
613425bb815Sopenharmony_ci  if (copy_bytecode
614425bb815Sopenharmony_ci      || (header_size + (literal_end * sizeof (uint16_t)) + BYTECODE_NO_COPY_THRESHOLD > code_size))
615425bb815Sopenharmony_ci  {
616425bb815Sopenharmony_ci    bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (code_size);
617425bb815Sopenharmony_ci
618425bb815Sopenharmony_ci#if ENABLED (JERRY_MEM_STATS)
619425bb815Sopenharmony_ci    jmem_stats_allocate_byte_code_bytes (code_size);
620425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_MEM_STATS) */
621425bb815Sopenharmony_ci
622425bb815Sopenharmony_ci    memcpy (bytecode_p, base_addr_p, code_size);
623425bb815Sopenharmony_ci  }
624425bb815Sopenharmony_ci  else
625425bb815Sopenharmony_ci  {
626425bb815Sopenharmony_ci    uint32_t start_offset = (uint32_t) (header_size + literal_end * sizeof (ecma_value_t));
627425bb815Sopenharmony_ci
628425bb815Sopenharmony_ci    uint8_t *real_bytecode_p = ((uint8_t *) bytecode_p) + start_offset;
629425bb815Sopenharmony_ci    uint32_t new_code_size = (uint32_t) (start_offset + 1 + sizeof (uint8_t *));
630425bb815Sopenharmony_ci
631425bb815Sopenharmony_ci    if (argument_end != 0)
632425bb815Sopenharmony_ci    {
633425bb815Sopenharmony_ci      new_code_size += (uint32_t) (argument_end * sizeof (ecma_value_t));
634425bb815Sopenharmony_ci    }
635425bb815Sopenharmony_ci
636425bb815Sopenharmony_ci    new_code_size = JERRY_ALIGNUP (new_code_size, JMEM_ALIGNMENT);
637425bb815Sopenharmony_ci
638425bb815Sopenharmony_ci    bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (new_code_size);
639425bb815Sopenharmony_ci
640425bb815Sopenharmony_ci#if ENABLED (JERRY_MEM_STATS)
641425bb815Sopenharmony_ci    jmem_stats_allocate_byte_code_bytes (new_code_size);
642425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_MEM_STATS) */
643425bb815Sopenharmony_ci
644425bb815Sopenharmony_ci    memcpy (bytecode_p, base_addr_p, start_offset);
645425bb815Sopenharmony_ci
646425bb815Sopenharmony_ci    bytecode_p->size = (uint16_t) (new_code_size >> JMEM_ALIGNMENT_LOG);
647425bb815Sopenharmony_ci
648425bb815Sopenharmony_ci    uint8_t *byte_p = (uint8_t *) bytecode_p;
649425bb815Sopenharmony_ci
650425bb815Sopenharmony_ci    if (argument_end != 0)
651425bb815Sopenharmony_ci    {
652425bb815Sopenharmony_ci      uint32_t argument_size = (uint32_t) (argument_end * sizeof (ecma_value_t));
653425bb815Sopenharmony_ci      memcpy (byte_p + new_code_size - argument_size,
654425bb815Sopenharmony_ci              base_addr_p + code_size - argument_size,
655425bb815Sopenharmony_ci              argument_size);
656425bb815Sopenharmony_ci    }
657425bb815Sopenharmony_ci
658425bb815Sopenharmony_ci    byte_p[start_offset] = CBC_SET_BYTECODE_PTR;
659425bb815Sopenharmony_ci    memcpy (byte_p + start_offset + 1, &real_bytecode_p, sizeof (uint8_t *));
660425bb815Sopenharmony_ci
661425bb815Sopenharmony_ci    code_size = new_code_size;
662425bb815Sopenharmony_ci  }
663425bb815Sopenharmony_ci
664425bb815Sopenharmony_ci  JERRY_ASSERT (bytecode_p->refs == 1);
665425bb815Sopenharmony_ci
666425bb815Sopenharmony_ci#if ENABLED (JERRY_DEBUGGER)
667425bb815Sopenharmony_ci  bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags | CBC_CODE_FLAGS_DEBUGGER_IGNORE);
668425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_DEBUGGER) */
669425bb815Sopenharmony_ci
670425bb815Sopenharmony_ci  ecma_value_t *literal_start_p = (ecma_value_t *) (((uint8_t *) bytecode_p) + header_size);
671425bb815Sopenharmony_ci
672425bb815Sopenharmony_ci  for (uint32_t i = 0; i < const_literal_end; i++)
673425bb815Sopenharmony_ci  {
674425bb815Sopenharmony_ci    if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
675425bb815Sopenharmony_ci    {
676425bb815Sopenharmony_ci      literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
677425bb815Sopenharmony_ci    }
678425bb815Sopenharmony_ci  }
679425bb815Sopenharmony_ci
680425bb815Sopenharmony_ci  for (uint32_t i = const_literal_end; i < literal_end; i++)
681425bb815Sopenharmony_ci  {
682425bb815Sopenharmony_ci    size_t literal_offset = (size_t) literal_start_p[i];
683425bb815Sopenharmony_ci
684425bb815Sopenharmony_ci    if (literal_offset == 0)
685425bb815Sopenharmony_ci    {
686425bb815Sopenharmony_ci      /* Self reference */
687425bb815Sopenharmony_ci      ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i],
688425bb815Sopenharmony_ci                                       bytecode_p);
689425bb815Sopenharmony_ci    }
690425bb815Sopenharmony_ci    else
691425bb815Sopenharmony_ci    {
692425bb815Sopenharmony_ci      ecma_compiled_code_t *literal_bytecode_p;
693425bb815Sopenharmony_ci      literal_bytecode_p = snapshot_load_compiled_code (base_addr_p + literal_offset,
694425bb815Sopenharmony_ci                                                        literal_base_p,
695425bb815Sopenharmony_ci                                                        copy_bytecode);
696425bb815Sopenharmony_ci
697425bb815Sopenharmony_ci      ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i],
698425bb815Sopenharmony_ci                                       literal_bytecode_p);
699425bb815Sopenharmony_ci    }
700425bb815Sopenharmony_ci  }
701425bb815Sopenharmony_ci
702425bb815Sopenharmony_ci  if (argument_end != 0)
703425bb815Sopenharmony_ci  {
704425bb815Sopenharmony_ci    literal_start_p = (ecma_value_t *) (((uint8_t *) bytecode_p) + code_size);
705425bb815Sopenharmony_ci    literal_start_p -= argument_end;
706425bb815Sopenharmony_ci
707425bb815Sopenharmony_ci    for (uint32_t i = 0; i < argument_end; i++)
708425bb815Sopenharmony_ci    {
709425bb815Sopenharmony_ci      if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
710425bb815Sopenharmony_ci      {
711425bb815Sopenharmony_ci        literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
712425bb815Sopenharmony_ci      }
713425bb815Sopenharmony_ci    }
714425bb815Sopenharmony_ci  }
715425bb815Sopenharmony_ci
716425bb815Sopenharmony_ci  return bytecode_p;
717425bb815Sopenharmony_ci} /* snapshot_load_compiled_code */
718425bb815Sopenharmony_ci
719425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
720425bb815Sopenharmony_ci
721425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
722425bb815Sopenharmony_ci
723425bb815Sopenharmony_ci/**
724425bb815Sopenharmony_ci * Generate snapshot from specified source and arguments
725425bb815Sopenharmony_ci *
726425bb815Sopenharmony_ci * @return size of snapshot (a number value), if it was generated succesfully
727425bb815Sopenharmony_ci *          (i.e. there are no syntax errors in source code, buffer size is sufficient,
728425bb815Sopenharmony_ci *           and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
729425bb815Sopenharmony_ci *         error object otherwise
730425bb815Sopenharmony_ci */
731425bb815Sopenharmony_cistatic jerry_value_t
732425bb815Sopenharmony_cijerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< script resource name */
733425bb815Sopenharmony_ci                                   size_t resource_name_length, /**< script resource name length */
734425bb815Sopenharmony_ci                                   const jerry_char_t *source_p, /**< script source */
735425bb815Sopenharmony_ci                                   size_t source_size, /**< script source size */
736425bb815Sopenharmony_ci                                   const jerry_char_t *args_p, /**< arguments string */
737425bb815Sopenharmony_ci                                   size_t args_size, /**< arguments string size */
738425bb815Sopenharmony_ci                                   uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
739425bb815Sopenharmony_ci                                   uint32_t *buffer_p, /**< buffer to save snapshot to */
740425bb815Sopenharmony_ci                                   size_t buffer_size) /**< the buffer's size */
741425bb815Sopenharmony_ci{
742425bb815Sopenharmony_ci  /* Currently unused arguments. */
743425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_p);
744425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_length);
745425bb815Sopenharmony_ci
746425bb815Sopenharmony_ci#if ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM)
747425bb815Sopenharmony_ci  JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED;
748425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
749425bb815Sopenharmony_ci
750425bb815Sopenharmony_ci  snapshot_globals_t globals;
751425bb815Sopenharmony_ci  ecma_value_t parse_status;
752425bb815Sopenharmony_ci  ecma_compiled_code_t *bytecode_data_p;
753425bb815Sopenharmony_ci  const uint32_t aligned_header_size = JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t),
754425bb815Sopenharmony_ci                                                      JMEM_ALIGNMENT);
755425bb815Sopenharmony_ci
756425bb815Sopenharmony_ci  globals.snapshot_buffer_write_offset = aligned_header_size;
757425bb815Sopenharmony_ci  globals.snapshot_error = ECMA_VALUE_EMPTY;
758425bb815Sopenharmony_ci  globals.regex_found = false;
759425bb815Sopenharmony_ci  globals.class_found = false;
760425bb815Sopenharmony_ci
761425bb815Sopenharmony_ci  parse_status = parser_parse_script (args_p,
762425bb815Sopenharmony_ci                                      args_size,
763425bb815Sopenharmony_ci                                      source_p,
764425bb815Sopenharmony_ci                                      source_size,
765425bb815Sopenharmony_ci                                      (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STRICT) != 0,
766425bb815Sopenharmony_ci                                      &bytecode_data_p);
767425bb815Sopenharmony_ci
768425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (parse_status))
769425bb815Sopenharmony_ci  {
770425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
771425bb815Sopenharmony_ci  }
772425bb815Sopenharmony_ci
773425bb815Sopenharmony_ci  JERRY_ASSERT (bytecode_data_p != NULL);
774425bb815Sopenharmony_ci
775425bb815Sopenharmony_ci  if (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC)
776425bb815Sopenharmony_ci  {
777425bb815Sopenharmony_ci    static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals);
778425bb815Sopenharmony_ci  }
779425bb815Sopenharmony_ci  else
780425bb815Sopenharmony_ci  {
781425bb815Sopenharmony_ci    snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals);
782425bb815Sopenharmony_ci  }
783425bb815Sopenharmony_ci
784425bb815Sopenharmony_ci  if (!ecma_is_value_empty (globals.snapshot_error))
785425bb815Sopenharmony_ci  {
786425bb815Sopenharmony_ci    ecma_bytecode_deref (bytecode_data_p);
787425bb815Sopenharmony_ci    return globals.snapshot_error;
788425bb815Sopenharmony_ci  }
789425bb815Sopenharmony_ci
790425bb815Sopenharmony_ci  jerry_snapshot_header_t header;
791425bb815Sopenharmony_ci  header.magic = JERRY_SNAPSHOT_MAGIC;
792425bb815Sopenharmony_ci  header.version = JERRY_SNAPSHOT_VERSION;
793425bb815Sopenharmony_ci  header.global_flags = snapshot_get_global_flags (globals.regex_found, globals.class_found);
794425bb815Sopenharmony_ci  header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
795425bb815Sopenharmony_ci  header.number_of_funcs = 1;
796425bb815Sopenharmony_ci  header.func_offsets[0] = aligned_header_size;
797425bb815Sopenharmony_ci
798425bb815Sopenharmony_ci  lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
799425bb815Sopenharmony_ci  uint32_t literals_num = 0;
800425bb815Sopenharmony_ci
801425bb815Sopenharmony_ci  if (!(generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC))
802425bb815Sopenharmony_ci  {
803425bb815Sopenharmony_ci    ecma_collection_t *lit_pool_p = ecma_new_collection ();
804425bb815Sopenharmony_ci
805425bb815Sopenharmony_ci    ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p);
806425bb815Sopenharmony_ci
807425bb815Sopenharmony_ci    if (!ecma_save_literals_for_snapshot (lit_pool_p,
808425bb815Sopenharmony_ci                                          buffer_p,
809425bb815Sopenharmony_ci                                          buffer_size,
810425bb815Sopenharmony_ci                                          &globals.snapshot_buffer_write_offset,
811425bb815Sopenharmony_ci                                          &lit_map_p,
812425bb815Sopenharmony_ci                                          &literals_num))
813425bb815Sopenharmony_ci    {
814425bb815Sopenharmony_ci      JERRY_ASSERT (lit_map_p == NULL);
815425bb815Sopenharmony_ci      const char * const error_message_p = "Cannot allocate memory for literals.";
816425bb815Sopenharmony_ci      ecma_bytecode_deref (bytecode_data_p);
817425bb815Sopenharmony_ci      return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) error_message_p);
818425bb815Sopenharmony_ci    }
819425bb815Sopenharmony_ci
820425bb815Sopenharmony_ci    jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)),
821425bb815Sopenharmony_ci                                (uint32_t) (header.lit_table_offset - aligned_header_size),
822425bb815Sopenharmony_ci                                lit_map_p);
823425bb815Sopenharmony_ci  }
824425bb815Sopenharmony_ci
825425bb815Sopenharmony_ci  size_t header_offset = 0;
826425bb815Sopenharmony_ci
827425bb815Sopenharmony_ci  snapshot_write_to_buffer_by_offset ((uint8_t *) buffer_p,
828425bb815Sopenharmony_ci                                      buffer_size,
829425bb815Sopenharmony_ci                                      &header_offset,
830425bb815Sopenharmony_ci                                      &header,
831425bb815Sopenharmony_ci                                      sizeof (header));
832425bb815Sopenharmony_ci
833425bb815Sopenharmony_ci  if (lit_map_p != NULL)
834425bb815Sopenharmony_ci  {
835425bb815Sopenharmony_ci    jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
836425bb815Sopenharmony_ci  }
837425bb815Sopenharmony_ci
838425bb815Sopenharmony_ci  ecma_bytecode_deref (bytecode_data_p);
839425bb815Sopenharmony_ci
840425bb815Sopenharmony_ci  return ecma_make_number_value ((ecma_number_t) globals.snapshot_buffer_write_offset);
841425bb815Sopenharmony_ci} /* jerry_generate_snapshot_with_args */
842425bb815Sopenharmony_ci
843425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
844425bb815Sopenharmony_ci
845425bb815Sopenharmony_ci/**
846425bb815Sopenharmony_ci * Generate snapshot from specified source and arguments
847425bb815Sopenharmony_ci *
848425bb815Sopenharmony_ci * @return size of snapshot (a number value), if it was generated succesfully
849425bb815Sopenharmony_ci *          (i.e. there are no syntax errors in source code, buffer size is sufficient,
850425bb815Sopenharmony_ci *           and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
851425bb815Sopenharmony_ci *         error object otherwise
852425bb815Sopenharmony_ci */
853425bb815Sopenharmony_cijerry_value_t
854425bb815Sopenharmony_cijerry_generate_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */
855425bb815Sopenharmony_ci                         size_t resource_name_length, /**< script resource name length */
856425bb815Sopenharmony_ci                         const jerry_char_t *source_p, /**< script source */
857425bb815Sopenharmony_ci                         size_t source_size, /**< script source size */
858425bb815Sopenharmony_ci                         uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
859425bb815Sopenharmony_ci                         uint32_t *buffer_p, /**< buffer to save snapshot to */
860425bb815Sopenharmony_ci                         size_t buffer_size) /**< the buffer's size */
861425bb815Sopenharmony_ci{
862425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
863425bb815Sopenharmony_ci  uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT);
864425bb815Sopenharmony_ci
865425bb815Sopenharmony_ci  if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
866425bb815Sopenharmony_ci  {
867425bb815Sopenharmony_ci    const char * const error_message_p = "Unsupported generate snapshot flags specified.";
868425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
869425bb815Sopenharmony_ci  }
870425bb815Sopenharmony_ci
871425bb815Sopenharmony_ci  return jerry_generate_snapshot_with_args (resource_name_p,
872425bb815Sopenharmony_ci                                            resource_name_length,
873425bb815Sopenharmony_ci                                            source_p,
874425bb815Sopenharmony_ci                                            source_size,
875425bb815Sopenharmony_ci                                            NULL,
876425bb815Sopenharmony_ci                                            0,
877425bb815Sopenharmony_ci                                            generate_snapshot_opts,
878425bb815Sopenharmony_ci                                            buffer_p,
879425bb815Sopenharmony_ci                                            buffer_size);
880425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
881425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_p);
882425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_length);
883425bb815Sopenharmony_ci  JERRY_UNUSED (source_p);
884425bb815Sopenharmony_ci  JERRY_UNUSED (source_size);
885425bb815Sopenharmony_ci  JERRY_UNUSED (generate_snapshot_opts);
886425bb815Sopenharmony_ci  JERRY_UNUSED (buffer_p);
887425bb815Sopenharmony_ci  JERRY_UNUSED (buffer_size);
888425bb815Sopenharmony_ci
889425bb815Sopenharmony_ci  return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot save is not supported.");
890425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
891425bb815Sopenharmony_ci} /* jerry_generate_snapshot */
892425bb815Sopenharmony_ci
893425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_EXEC)
894425bb815Sopenharmony_ci/**
895425bb815Sopenharmony_ci * Execute/load snapshot from specified buffer
896425bb815Sopenharmony_ci *
897425bb815Sopenharmony_ci * Note:
898425bb815Sopenharmony_ci *      returned value must be freed with jerry_release_value, when it is no longer needed.
899425bb815Sopenharmony_ci *
900425bb815Sopenharmony_ci * @return result of bytecode - if run was successful
901425bb815Sopenharmony_ci *         thrown error - otherwise
902425bb815Sopenharmony_ci */
903425bb815Sopenharmony_cistatic jerry_value_t
904425bb815Sopenharmony_cijerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */
905425bb815Sopenharmony_ci                       size_t snapshot_size, /**< size of snapshot */
906425bb815Sopenharmony_ci                       size_t func_index, /**< index of primary function */
907425bb815Sopenharmony_ci                       uint32_t exec_snapshot_opts, /**< jerry_exec_snapshot_opts_t option bits */
908425bb815Sopenharmony_ci                       bool as_function) /** < specify if the loaded snapshot should be returned as a function */
909425bb815Sopenharmony_ci{
910425bb815Sopenharmony_ci  JERRY_ASSERT (snapshot_p != NULL);
911425bb815Sopenharmony_ci
912425bb815Sopenharmony_ci  uint32_t allowed_opts = (JERRY_SNAPSHOT_EXEC_COPY_DATA | JERRY_SNAPSHOT_EXEC_ALLOW_STATIC);
913425bb815Sopenharmony_ci
914425bb815Sopenharmony_ci  if ((exec_snapshot_opts & ~(allowed_opts)) != 0)
915425bb815Sopenharmony_ci  {
916425bb815Sopenharmony_ci    ecma_raise_range_error (ECMA_ERR_MSG ("Unsupported exec snapshot flags specified."));
917425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
918425bb815Sopenharmony_ci  }
919425bb815Sopenharmony_ci
920425bb815Sopenharmony_ci  const char * const invalid_version_error_p = "Invalid snapshot version or unsupported features present";
921425bb815Sopenharmony_ci  const char * const invalid_format_error_p = "Invalid snapshot format";
922425bb815Sopenharmony_ci  const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
923425bb815Sopenharmony_ci
924425bb815Sopenharmony_ci  if (snapshot_size <= sizeof (jerry_snapshot_header_t))
925425bb815Sopenharmony_ci  {
926425bb815Sopenharmony_ci    ecma_raise_type_error (invalid_format_error_p);
927425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
928425bb815Sopenharmony_ci  }
929425bb815Sopenharmony_ci
930425bb815Sopenharmony_ci  const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
931425bb815Sopenharmony_ci
932425bb815Sopenharmony_ci  if (header_p->magic != JERRY_SNAPSHOT_MAGIC
933425bb815Sopenharmony_ci      || header_p->version != JERRY_SNAPSHOT_VERSION
934425bb815Sopenharmony_ci      || !snapshot_check_global_flags (header_p->global_flags))
935425bb815Sopenharmony_ci  {
936425bb815Sopenharmony_ci    ecma_raise_type_error (invalid_version_error_p);
937425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
938425bb815Sopenharmony_ci  }
939425bb815Sopenharmony_ci
940425bb815Sopenharmony_ci  if (header_p->lit_table_offset > snapshot_size)
941425bb815Sopenharmony_ci  {
942425bb815Sopenharmony_ci    ecma_raise_type_error (invalid_version_error_p);
943425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
944425bb815Sopenharmony_ci  }
945425bb815Sopenharmony_ci
946425bb815Sopenharmony_ci  if (func_index >= header_p->number_of_funcs)
947425bb815Sopenharmony_ci  {
948425bb815Sopenharmony_ci    ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum"));
949425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
950425bb815Sopenharmony_ci  }
951425bb815Sopenharmony_ci
952425bb815Sopenharmony_ci  JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
953425bb815Sopenharmony_ci
954425bb815Sopenharmony_ci  uint32_t func_offset = header_p->func_offsets[func_index];
955425bb815Sopenharmony_ci  ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + func_offset);
956425bb815Sopenharmony_ci
957425bb815Sopenharmony_ci  if (bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)
958425bb815Sopenharmony_ci  {
959425bb815Sopenharmony_ci    if (!(exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_ALLOW_STATIC))
960425bb815Sopenharmony_ci    {
961425bb815Sopenharmony_ci      ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots not allowed"));
962425bb815Sopenharmony_ci      return ecma_create_error_reference_from_context ();
963425bb815Sopenharmony_ci    }
964425bb815Sopenharmony_ci
965425bb815Sopenharmony_ci    if (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA)
966425bb815Sopenharmony_ci    {
967425bb815Sopenharmony_ci      ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots cannot be copied into memory"));
968425bb815Sopenharmony_ci      return ecma_create_error_reference_from_context ();
969425bb815Sopenharmony_ci    }
970425bb815Sopenharmony_ci  }
971425bb815Sopenharmony_ci  else
972425bb815Sopenharmony_ci  {
973425bb815Sopenharmony_ci    const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
974425bb815Sopenharmony_ci
975425bb815Sopenharmony_ci    bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p,
976425bb815Sopenharmony_ci                                              literal_base_p,
977425bb815Sopenharmony_ci                                              (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA) != 0);
978425bb815Sopenharmony_ci
979425bb815Sopenharmony_ci    if (bytecode_p == NULL)
980425bb815Sopenharmony_ci    {
981425bb815Sopenharmony_ci      return ecma_raise_type_error (invalid_format_error_p);
982425bb815Sopenharmony_ci    }
983425bb815Sopenharmony_ci  }
984425bb815Sopenharmony_ci
985425bb815Sopenharmony_ci  ecma_value_t ret_val;
986425bb815Sopenharmony_ci
987425bb815Sopenharmony_ci  if (as_function)
988425bb815Sopenharmony_ci  {
989425bb815Sopenharmony_ci#if ENABLED (JERRY_ES2015)
990425bb815Sopenharmony_ci    if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED)
991425bb815Sopenharmony_ci    {
992425bb815Sopenharmony_ci      ecma_create_global_lexical_block ();
993425bb815Sopenharmony_ci    }
994425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_ES2015) */
995425bb815Sopenharmony_ci
996425bb815Sopenharmony_ci    ecma_object_t *lex_env_p = ecma_get_global_scope ();
997425bb815Sopenharmony_ci    ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p);
998425bb815Sopenharmony_ci
999425bb815Sopenharmony_ci    if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1000425bb815Sopenharmony_ci    {
1001425bb815Sopenharmony_ci      ecma_bytecode_deref (bytecode_p);
1002425bb815Sopenharmony_ci    }
1003425bb815Sopenharmony_ci    ret_val = ecma_make_object_value (func_obj_p);
1004425bb815Sopenharmony_ci  }
1005425bb815Sopenharmony_ci  else
1006425bb815Sopenharmony_ci  {
1007425bb815Sopenharmony_ci    ret_val = vm_run_global (bytecode_p);
1008425bb815Sopenharmony_ci    if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1009425bb815Sopenharmony_ci    {
1010425bb815Sopenharmony_ci      ecma_bytecode_deref (bytecode_p);
1011425bb815Sopenharmony_ci    }
1012425bb815Sopenharmony_ci  }
1013425bb815Sopenharmony_ci
1014425bb815Sopenharmony_ci  if (ECMA_IS_VALUE_ERROR (ret_val))
1015425bb815Sopenharmony_ci  {
1016425bb815Sopenharmony_ci    return ecma_create_error_reference_from_context ();
1017425bb815Sopenharmony_ci  }
1018425bb815Sopenharmony_ci
1019425bb815Sopenharmony_ci  return ret_val;
1020425bb815Sopenharmony_ci} /* jerry_snapshot_result */
1021425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1022425bb815Sopenharmony_ci
1023425bb815Sopenharmony_ci/**
1024425bb815Sopenharmony_ci * Execute snapshot from specified buffer
1025425bb815Sopenharmony_ci *
1026425bb815Sopenharmony_ci * Note:
1027425bb815Sopenharmony_ci *      returned value must be freed with jerry_release_value, when it is no longer needed.
1028425bb815Sopenharmony_ci *
1029425bb815Sopenharmony_ci * @return result of bytecode - if run was successful
1030425bb815Sopenharmony_ci *         thrown error - otherwise
1031425bb815Sopenharmony_ci */
1032425bb815Sopenharmony_cijerry_value_t
1033425bb815Sopenharmony_cijerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
1034425bb815Sopenharmony_ci                     size_t snapshot_size, /**< size of snapshot */
1035425bb815Sopenharmony_ci                     size_t func_index, /**< index of primary function */
1036425bb815Sopenharmony_ci                     uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */
1037425bb815Sopenharmony_ci{
1038425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_EXEC)
1039425bb815Sopenharmony_ci  return jerry_snapshot_result (snapshot_p, snapshot_size, func_index, exec_snapshot_opts, false);
1040425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
1041425bb815Sopenharmony_ci  JERRY_UNUSED (snapshot_p);
1042425bb815Sopenharmony_ci  JERRY_UNUSED (snapshot_size);
1043425bb815Sopenharmony_ci  JERRY_UNUSED (func_index);
1044425bb815Sopenharmony_ci  JERRY_UNUSED (exec_snapshot_opts);
1045425bb815Sopenharmony_ci
1046425bb815Sopenharmony_ci  return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot execution is not supported.");
1047425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1048425bb815Sopenharmony_ci} /* jerry_exec_snapshot */
1049425bb815Sopenharmony_ci
1050425bb815Sopenharmony_ci/**
1051425bb815Sopenharmony_ci * @}
1052425bb815Sopenharmony_ci */
1053425bb815Sopenharmony_ci
1054425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
1055425bb815Sopenharmony_ci
1056425bb815Sopenharmony_ci/**
1057425bb815Sopenharmony_ci * Collect all literals from a snapshot file.
1058425bb815Sopenharmony_ci */
1059425bb815Sopenharmony_cistatic void
1060425bb815Sopenharmony_ciscan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */
1061425bb815Sopenharmony_ci                         const uint8_t *buffer_end_p, /**< snapshot buffer end */
1062425bb815Sopenharmony_ci                         ecma_collection_t *lit_pool_p, /**< list of known values */
1063425bb815Sopenharmony_ci                         const uint8_t *literal_base_p) /**< start of literal data */
1064425bb815Sopenharmony_ci{
1065425bb815Sopenharmony_ci  JERRY_ASSERT (buffer_end_p > buffer_p);
1066425bb815Sopenharmony_ci
1067425bb815Sopenharmony_ci  do
1068425bb815Sopenharmony_ci  {
1069425bb815Sopenharmony_ci    const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
1070425bb815Sopenharmony_ci    uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1071425bb815Sopenharmony_ci
1072425bb815Sopenharmony_ci    if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
1073425bb815Sopenharmony_ci        && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1074425bb815Sopenharmony_ci    {
1075425bb815Sopenharmony_ci      const ecma_value_t *literal_start_p;
1076425bb815Sopenharmony_ci      uint32_t argument_end;
1077425bb815Sopenharmony_ci      uint32_t const_literal_end;
1078425bb815Sopenharmony_ci
1079425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1080425bb815Sopenharmony_ci      {
1081425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
1082425bb815Sopenharmony_ci
1083425bb815Sopenharmony_ci        cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
1084425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
1085425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1086425bb815Sopenharmony_ci      }
1087425bb815Sopenharmony_ci      else
1088425bb815Sopenharmony_ci      {
1089425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
1090425bb815Sopenharmony_ci
1091425bb815Sopenharmony_ci        cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
1092425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
1093425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1094425bb815Sopenharmony_ci      }
1095425bb815Sopenharmony_ci
1096425bb815Sopenharmony_ci      for (uint32_t i = 0; i < const_literal_end; i++)
1097425bb815Sopenharmony_ci      {
1098425bb815Sopenharmony_ci        if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1099425bb815Sopenharmony_ci        {
1100425bb815Sopenharmony_ci          ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1101425bb815Sopenharmony_ci          ecma_save_literals_append_value (lit_value, lit_pool_p);
1102425bb815Sopenharmony_ci        }
1103425bb815Sopenharmony_ci      }
1104425bb815Sopenharmony_ci
1105425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
1106425bb815Sopenharmony_ci      {
1107425bb815Sopenharmony_ci        uint8_t *byte_p = (uint8_t *) bytecode_p;
1108425bb815Sopenharmony_ci        byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1109425bb815Sopenharmony_ci        literal_start_p = ((ecma_value_t *) byte_p) - argument_end;
1110425bb815Sopenharmony_ci
1111425bb815Sopenharmony_ci        for (uint32_t i = 0; i < argument_end; i++)
1112425bb815Sopenharmony_ci        {
1113425bb815Sopenharmony_ci          if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1114425bb815Sopenharmony_ci          {
1115425bb815Sopenharmony_ci            ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1116425bb815Sopenharmony_ci            ecma_save_literals_append_value (lit_value, lit_pool_p);
1117425bb815Sopenharmony_ci          }
1118425bb815Sopenharmony_ci        }
1119425bb815Sopenharmony_ci      }
1120425bb815Sopenharmony_ci    }
1121425bb815Sopenharmony_ci
1122425bb815Sopenharmony_ci    buffer_p += code_size;
1123425bb815Sopenharmony_ci  }
1124425bb815Sopenharmony_ci  while (buffer_p < buffer_end_p);
1125425bb815Sopenharmony_ci} /* scan_snapshot_functions */
1126425bb815Sopenharmony_ci
1127425bb815Sopenharmony_ci/**
1128425bb815Sopenharmony_ci * Update all literal offsets in a snapshot data.
1129425bb815Sopenharmony_ci */
1130425bb815Sopenharmony_cistatic void
1131425bb815Sopenharmony_ciupdate_literal_offsets (uint8_t *buffer_p, /**< [in,out] snapshot buffer start */
1132425bb815Sopenharmony_ci                        const uint8_t *buffer_end_p, /**< snapshot buffer end */
1133425bb815Sopenharmony_ci                        const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
1134425bb815Sopenharmony_ci                        const uint8_t *literal_base_p) /**< start of literal data */
1135425bb815Sopenharmony_ci{
1136425bb815Sopenharmony_ci  JERRY_ASSERT (buffer_end_p > buffer_p);
1137425bb815Sopenharmony_ci
1138425bb815Sopenharmony_ci  do
1139425bb815Sopenharmony_ci  {
1140425bb815Sopenharmony_ci    const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
1141425bb815Sopenharmony_ci    uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1142425bb815Sopenharmony_ci
1143425bb815Sopenharmony_ci    if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
1144425bb815Sopenharmony_ci        && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1145425bb815Sopenharmony_ci    {
1146425bb815Sopenharmony_ci      ecma_value_t *literal_start_p;
1147425bb815Sopenharmony_ci      uint32_t argument_end;
1148425bb815Sopenharmony_ci      uint32_t const_literal_end;
1149425bb815Sopenharmony_ci
1150425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1151425bb815Sopenharmony_ci      {
1152425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
1153425bb815Sopenharmony_ci
1154425bb815Sopenharmony_ci        cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
1155425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
1156425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1157425bb815Sopenharmony_ci      }
1158425bb815Sopenharmony_ci      else
1159425bb815Sopenharmony_ci      {
1160425bb815Sopenharmony_ci        literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
1161425bb815Sopenharmony_ci
1162425bb815Sopenharmony_ci        cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
1163425bb815Sopenharmony_ci        argument_end = args_p->argument_end;
1164425bb815Sopenharmony_ci        const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1165425bb815Sopenharmony_ci      }
1166425bb815Sopenharmony_ci
1167425bb815Sopenharmony_ci      for (uint32_t i = 0; i < const_literal_end; i++)
1168425bb815Sopenharmony_ci      {
1169425bb815Sopenharmony_ci        if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1170425bb815Sopenharmony_ci        {
1171425bb815Sopenharmony_ci          ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1172425bb815Sopenharmony_ci          const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
1173425bb815Sopenharmony_ci
1174425bb815Sopenharmony_ci          while (current_p->literal_id != lit_value)
1175425bb815Sopenharmony_ci          {
1176425bb815Sopenharmony_ci            current_p++;
1177425bb815Sopenharmony_ci          }
1178425bb815Sopenharmony_ci
1179425bb815Sopenharmony_ci          literal_start_p[i] = current_p->literal_offset;
1180425bb815Sopenharmony_ci        }
1181425bb815Sopenharmony_ci      }
1182425bb815Sopenharmony_ci
1183425bb815Sopenharmony_ci      if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
1184425bb815Sopenharmony_ci      {
1185425bb815Sopenharmony_ci        uint8_t *byte_p = (uint8_t *) bytecode_p;
1186425bb815Sopenharmony_ci        byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1187425bb815Sopenharmony_ci        literal_start_p = ((ecma_value_t *) byte_p) - argument_end;
1188425bb815Sopenharmony_ci
1189425bb815Sopenharmony_ci        for (uint32_t i = 0; i < argument_end; i++)
1190425bb815Sopenharmony_ci        {
1191425bb815Sopenharmony_ci          if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1192425bb815Sopenharmony_ci          {
1193425bb815Sopenharmony_ci            ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1194425bb815Sopenharmony_ci            const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
1195425bb815Sopenharmony_ci
1196425bb815Sopenharmony_ci            while (current_p->literal_id != lit_value)
1197425bb815Sopenharmony_ci            {
1198425bb815Sopenharmony_ci              current_p++;
1199425bb815Sopenharmony_ci            }
1200425bb815Sopenharmony_ci
1201425bb815Sopenharmony_ci            literal_start_p[i] = current_p->literal_offset;
1202425bb815Sopenharmony_ci          }
1203425bb815Sopenharmony_ci        }
1204425bb815Sopenharmony_ci      }
1205425bb815Sopenharmony_ci    }
1206425bb815Sopenharmony_ci
1207425bb815Sopenharmony_ci    buffer_p += code_size;
1208425bb815Sopenharmony_ci  }
1209425bb815Sopenharmony_ci  while (buffer_p < buffer_end_p);
1210425bb815Sopenharmony_ci} /* update_literal_offsets */
1211425bb815Sopenharmony_ci
1212425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1213425bb815Sopenharmony_ci
1214425bb815Sopenharmony_ci/**
1215425bb815Sopenharmony_ci * Merge multiple snapshots into a single buffer
1216425bb815Sopenharmony_ci *
1217425bb815Sopenharmony_ci * @return length of merged snapshot file
1218425bb815Sopenharmony_ci *         0 on error
1219425bb815Sopenharmony_ci */
1220425bb815Sopenharmony_cisize_t
1221425bb815Sopenharmony_cijerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers to start of) input buffers */
1222425bb815Sopenharmony_ci                       size_t *inp_buffer_sizes_p, /**< array of input buffer sizes */
1223425bb815Sopenharmony_ci                       size_t number_of_snapshots, /**< number of snapshots */
1224425bb815Sopenharmony_ci                       uint32_t *out_buffer_p, /**< output buffer */
1225425bb815Sopenharmony_ci                       size_t out_buffer_size, /**< output buffer size */
1226425bb815Sopenharmony_ci                       const char **error_p) /**< error description */
1227425bb815Sopenharmony_ci{
1228425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
1229425bb815Sopenharmony_ci  uint32_t number_of_funcs = 0;
1230425bb815Sopenharmony_ci  uint32_t merged_global_flags = 0;
1231425bb815Sopenharmony_ci  size_t functions_size = sizeof (jerry_snapshot_header_t);
1232425bb815Sopenharmony_ci
1233425bb815Sopenharmony_ci  if (number_of_snapshots < 2)
1234425bb815Sopenharmony_ci  {
1235425bb815Sopenharmony_ci    *error_p = "at least two snapshots must be passed";
1236425bb815Sopenharmony_ci    return 0;
1237425bb815Sopenharmony_ci  }
1238425bb815Sopenharmony_ci
1239425bb815Sopenharmony_ci  ecma_collection_t *lit_pool_p = ecma_new_collection ();
1240425bb815Sopenharmony_ci
1241425bb815Sopenharmony_ci  for (uint32_t i = 0; i < number_of_snapshots; i++)
1242425bb815Sopenharmony_ci  {
1243425bb815Sopenharmony_ci    if (inp_buffer_sizes_p[i] < sizeof (jerry_snapshot_header_t))
1244425bb815Sopenharmony_ci    {
1245425bb815Sopenharmony_ci      *error_p = "invalid snapshot file";
1246425bb815Sopenharmony_ci      ecma_collection_destroy (lit_pool_p);
1247425bb815Sopenharmony_ci      return 0;
1248425bb815Sopenharmony_ci    }
1249425bb815Sopenharmony_ci
1250425bb815Sopenharmony_ci    const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
1251425bb815Sopenharmony_ci
1252425bb815Sopenharmony_ci    if (header_p->magic != JERRY_SNAPSHOT_MAGIC
1253425bb815Sopenharmony_ci        || header_p->version != JERRY_SNAPSHOT_VERSION
1254425bb815Sopenharmony_ci        || !snapshot_check_global_flags (header_p->global_flags))
1255425bb815Sopenharmony_ci    {
1256425bb815Sopenharmony_ci      *error_p = "invalid snapshot version or unsupported features present";
1257425bb815Sopenharmony_ci      ecma_collection_destroy (lit_pool_p);
1258425bb815Sopenharmony_ci      return 0;
1259425bb815Sopenharmony_ci    }
1260425bb815Sopenharmony_ci
1261425bb815Sopenharmony_ci    merged_global_flags |= header_p->global_flags;
1262425bb815Sopenharmony_ci
1263425bb815Sopenharmony_ci    uint32_t start_offset = header_p->func_offsets[0];
1264425bb815Sopenharmony_ci    const uint8_t *data_p = (const uint8_t *) inp_buffers_p[i];
1265425bb815Sopenharmony_ci    const uint8_t *literal_base_p = data_p + header_p->lit_table_offset;
1266425bb815Sopenharmony_ci
1267425bb815Sopenharmony_ci    JERRY_ASSERT (header_p->number_of_funcs > 0);
1268425bb815Sopenharmony_ci
1269425bb815Sopenharmony_ci    number_of_funcs += header_p->number_of_funcs;
1270425bb815Sopenharmony_ci    functions_size += header_p->lit_table_offset - start_offset;
1271425bb815Sopenharmony_ci
1272425bb815Sopenharmony_ci    scan_snapshot_functions (data_p + start_offset,
1273425bb815Sopenharmony_ci                             literal_base_p,
1274425bb815Sopenharmony_ci                             lit_pool_p,
1275425bb815Sopenharmony_ci                             literal_base_p);
1276425bb815Sopenharmony_ci  }
1277425bb815Sopenharmony_ci
1278425bb815Sopenharmony_ci  JERRY_ASSERT (number_of_funcs > 0);
1279425bb815Sopenharmony_ci
1280425bb815Sopenharmony_ci  functions_size += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
1281425bb815Sopenharmony_ci
1282425bb815Sopenharmony_ci  if (functions_size >= out_buffer_size)
1283425bb815Sopenharmony_ci  {
1284425bb815Sopenharmony_ci    *error_p = "output buffer is too small";
1285425bb815Sopenharmony_ci    ecma_collection_destroy (lit_pool_p);
1286425bb815Sopenharmony_ci    return 0;
1287425bb815Sopenharmony_ci  }
1288425bb815Sopenharmony_ci
1289425bb815Sopenharmony_ci  jerry_snapshot_header_t *header_p = (jerry_snapshot_header_t *) out_buffer_p;
1290425bb815Sopenharmony_ci
1291425bb815Sopenharmony_ci  header_p->magic = JERRY_SNAPSHOT_MAGIC;
1292425bb815Sopenharmony_ci  header_p->version = JERRY_SNAPSHOT_VERSION;
1293425bb815Sopenharmony_ci  header_p->global_flags = merged_global_flags;
1294425bb815Sopenharmony_ci  header_p->lit_table_offset = (uint32_t) functions_size;
1295425bb815Sopenharmony_ci  header_p->number_of_funcs = number_of_funcs;
1296425bb815Sopenharmony_ci
1297425bb815Sopenharmony_ci  lit_mem_to_snapshot_id_map_entry_t *lit_map_p;
1298425bb815Sopenharmony_ci  uint32_t literals_num;
1299425bb815Sopenharmony_ci
1300425bb815Sopenharmony_ci  if (!ecma_save_literals_for_snapshot (lit_pool_p,
1301425bb815Sopenharmony_ci                                        out_buffer_p,
1302425bb815Sopenharmony_ci                                        out_buffer_size,
1303425bb815Sopenharmony_ci                                        &functions_size,
1304425bb815Sopenharmony_ci                                        &lit_map_p,
1305425bb815Sopenharmony_ci                                        &literals_num))
1306425bb815Sopenharmony_ci  {
1307425bb815Sopenharmony_ci    *error_p = "buffer is too small";
1308425bb815Sopenharmony_ci    return 0;
1309425bb815Sopenharmony_ci  }
1310425bb815Sopenharmony_ci
1311425bb815Sopenharmony_ci  uint32_t *func_offset_p = header_p->func_offsets;
1312425bb815Sopenharmony_ci  uint8_t *dst_p = ((uint8_t *) out_buffer_p) + sizeof (jerry_snapshot_header_t);
1313425bb815Sopenharmony_ci  dst_p += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
1314425bb815Sopenharmony_ci
1315425bb815Sopenharmony_ci  for (uint32_t i = 0; i < number_of_snapshots; i++)
1316425bb815Sopenharmony_ci  {
1317425bb815Sopenharmony_ci    const jerry_snapshot_header_t *current_header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
1318425bb815Sopenharmony_ci
1319425bb815Sopenharmony_ci    uint32_t start_offset = current_header_p->func_offsets[0];
1320425bb815Sopenharmony_ci
1321425bb815Sopenharmony_ci    memcpy (dst_p,
1322425bb815Sopenharmony_ci            ((const uint8_t *) inp_buffers_p[i]) + start_offset,
1323425bb815Sopenharmony_ci            current_header_p->lit_table_offset - start_offset);
1324425bb815Sopenharmony_ci
1325425bb815Sopenharmony_ci    const uint8_t *literal_base_p = ((const uint8_t *) inp_buffers_p[i]) + current_header_p->lit_table_offset;
1326425bb815Sopenharmony_ci    update_literal_offsets (dst_p,
1327425bb815Sopenharmony_ci                            dst_p + current_header_p->lit_table_offset - start_offset,
1328425bb815Sopenharmony_ci                            lit_map_p,
1329425bb815Sopenharmony_ci                            literal_base_p);
1330425bb815Sopenharmony_ci
1331425bb815Sopenharmony_ci    uint32_t current_offset = (uint32_t) (dst_p - (uint8_t *) out_buffer_p) - start_offset;
1332425bb815Sopenharmony_ci
1333425bb815Sopenharmony_ci    for (uint32_t j = 0; j < current_header_p->number_of_funcs; j++)
1334425bb815Sopenharmony_ci    {
1335425bb815Sopenharmony_ci      /* Updating offset without changing any flags. */
1336425bb815Sopenharmony_ci      *func_offset_p++ = current_header_p->func_offsets[j] + current_offset;
1337425bb815Sopenharmony_ci    }
1338425bb815Sopenharmony_ci
1339425bb815Sopenharmony_ci    dst_p += current_header_p->lit_table_offset - start_offset;
1340425bb815Sopenharmony_ci  }
1341425bb815Sopenharmony_ci
1342425bb815Sopenharmony_ci  JERRY_ASSERT ((uint32_t) (dst_p - (uint8_t *) out_buffer_p) == header_p->lit_table_offset);
1343425bb815Sopenharmony_ci
1344425bb815Sopenharmony_ci  if (lit_map_p != NULL)
1345425bb815Sopenharmony_ci  {
1346425bb815Sopenharmony_ci    jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
1347425bb815Sopenharmony_ci  }
1348425bb815Sopenharmony_ci
1349425bb815Sopenharmony_ci  *error_p = NULL;
1350425bb815Sopenharmony_ci  return functions_size;
1351425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1352425bb815Sopenharmony_ci  JERRY_UNUSED (inp_buffers_p);
1353425bb815Sopenharmony_ci  JERRY_UNUSED (inp_buffer_sizes_p);
1354425bb815Sopenharmony_ci  JERRY_UNUSED (number_of_snapshots);
1355425bb815Sopenharmony_ci  JERRY_UNUSED (out_buffer_p);
1356425bb815Sopenharmony_ci  JERRY_UNUSED (out_buffer_size);
1357425bb815Sopenharmony_ci  JERRY_UNUSED (error_p);
1358425bb815Sopenharmony_ci
1359425bb815Sopenharmony_ci  *error_p = "snapshot merge not supported";
1360425bb815Sopenharmony_ci  return 0;
1361425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1362425bb815Sopenharmony_ci} /* jerry_merge_snapshots */
1363425bb815Sopenharmony_ci
1364425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
1365425bb815Sopenharmony_ci
1366425bb815Sopenharmony_ci/**
1367425bb815Sopenharmony_ci * ====================== Functions for literal saving ==========================
1368425bb815Sopenharmony_ci */
1369425bb815Sopenharmony_ci
1370425bb815Sopenharmony_ci/**
1371425bb815Sopenharmony_ci * Compare two ecma_strings by size, then lexicographically.
1372425bb815Sopenharmony_ci *
1373425bb815Sopenharmony_ci * @return true - if the first string is less than the second one,
1374425bb815Sopenharmony_ci *         false - otherwise
1375425bb815Sopenharmony_ci */
1376425bb815Sopenharmony_cistatic bool
1377425bb815Sopenharmony_cijerry_save_literals_compare (ecma_string_t *literal1, /**< first literal */
1378425bb815Sopenharmony_ci                             ecma_string_t *literal2) /**< second literal */
1379425bb815Sopenharmony_ci{
1380425bb815Sopenharmony_ci  const lit_utf8_size_t lit1_size = ecma_string_get_size (literal1);
1381425bb815Sopenharmony_ci  const lit_utf8_size_t lit2_size = ecma_string_get_size (literal2);
1382425bb815Sopenharmony_ci
1383425bb815Sopenharmony_ci  if (lit1_size == lit2_size)
1384425bb815Sopenharmony_ci  {
1385425bb815Sopenharmony_ci    return ecma_compare_ecma_strings_relational (literal1, literal2);
1386425bb815Sopenharmony_ci  }
1387425bb815Sopenharmony_ci
1388425bb815Sopenharmony_ci  return (lit1_size < lit2_size);
1389425bb815Sopenharmony_ci} /* jerry_save_literals_compare */
1390425bb815Sopenharmony_ci
1391425bb815Sopenharmony_ci/**
1392425bb815Sopenharmony_ci * Helper function for the heapsort algorithm.
1393425bb815Sopenharmony_ci *
1394425bb815Sopenharmony_ci * @return index of the maximum value
1395425bb815Sopenharmony_ci */
1396425bb815Sopenharmony_cistatic lit_utf8_size_t
1397425bb815Sopenharmony_cijerry_save_literals_heap_max (ecma_string_t *literals[], /**< array of literals */
1398425bb815Sopenharmony_ci                              lit_utf8_size_t num_of_nodes, /**< number of nodes */
1399425bb815Sopenharmony_ci                              lit_utf8_size_t node_idx, /**< index of parent node */
1400425bb815Sopenharmony_ci                              lit_utf8_size_t child_idx1, /**< index of the first child */
1401425bb815Sopenharmony_ci                              lit_utf8_size_t child_idx2) /**< index of the second child */
1402425bb815Sopenharmony_ci{
1403425bb815Sopenharmony_ci  lit_utf8_size_t max_idx = node_idx;
1404425bb815Sopenharmony_ci
1405425bb815Sopenharmony_ci  if (child_idx1 < num_of_nodes
1406425bb815Sopenharmony_ci      && jerry_save_literals_compare (literals[max_idx], literals[child_idx1]))
1407425bb815Sopenharmony_ci  {
1408425bb815Sopenharmony_ci    max_idx = child_idx1;
1409425bb815Sopenharmony_ci  }
1410425bb815Sopenharmony_ci
1411425bb815Sopenharmony_ci  if (child_idx2 < num_of_nodes
1412425bb815Sopenharmony_ci      && jerry_save_literals_compare (literals[max_idx], literals[child_idx2]))
1413425bb815Sopenharmony_ci  {
1414425bb815Sopenharmony_ci    max_idx = child_idx2;
1415425bb815Sopenharmony_ci  }
1416425bb815Sopenharmony_ci
1417425bb815Sopenharmony_ci  return max_idx;
1418425bb815Sopenharmony_ci} /* jerry_save_literals_heap_max */
1419425bb815Sopenharmony_ci
1420425bb815Sopenharmony_ci/**
1421425bb815Sopenharmony_ci * Helper function for the heapsort algorithm.
1422425bb815Sopenharmony_ci */
1423425bb815Sopenharmony_cistatic void
1424425bb815Sopenharmony_cijerry_save_literals_down_heap (ecma_string_t *literals[], /**< array of literals */
1425425bb815Sopenharmony_ci                               lit_utf8_size_t num_of_nodes, /**< number of nodes */
1426425bb815Sopenharmony_ci                               lit_utf8_size_t node_idx) /**< index of parent node */
1427425bb815Sopenharmony_ci{
1428425bb815Sopenharmony_ci  while (true)
1429425bb815Sopenharmony_ci  {
1430425bb815Sopenharmony_ci    lit_utf8_size_t max_idx = jerry_save_literals_heap_max (literals,
1431425bb815Sopenharmony_ci                                                            num_of_nodes,
1432425bb815Sopenharmony_ci                                                            node_idx,
1433425bb815Sopenharmony_ci                                                            2 * node_idx + 1,
1434425bb815Sopenharmony_ci                                                            2 * node_idx + 2);
1435425bb815Sopenharmony_ci    if (max_idx == node_idx)
1436425bb815Sopenharmony_ci    {
1437425bb815Sopenharmony_ci      break;
1438425bb815Sopenharmony_ci    }
1439425bb815Sopenharmony_ci
1440425bb815Sopenharmony_ci    ecma_string_t *tmp_str_p  = literals[node_idx];
1441425bb815Sopenharmony_ci    literals[node_idx] = literals[max_idx];
1442425bb815Sopenharmony_ci    literals[max_idx] = tmp_str_p;
1443425bb815Sopenharmony_ci
1444425bb815Sopenharmony_ci    node_idx = max_idx;
1445425bb815Sopenharmony_ci  }
1446425bb815Sopenharmony_ci} /* jerry_save_literals_down_heap */
1447425bb815Sopenharmony_ci
1448425bb815Sopenharmony_ci/**
1449425bb815Sopenharmony_ci * Helper function for a heapsort algorithm.
1450425bb815Sopenharmony_ci */
1451425bb815Sopenharmony_cistatic void
1452425bb815Sopenharmony_cijerry_save_literals_sort (ecma_string_t *literals[], /**< array of literals */
1453425bb815Sopenharmony_ci                          lit_utf8_size_t num_of_literals) /**< number of literals */
1454425bb815Sopenharmony_ci{
1455425bb815Sopenharmony_ci  if (num_of_literals < 2)
1456425bb815Sopenharmony_ci  {
1457425bb815Sopenharmony_ci    return;
1458425bb815Sopenharmony_ci  }
1459425bb815Sopenharmony_ci
1460425bb815Sopenharmony_ci  lit_utf8_size_t lit_idx = (num_of_literals - 2) / 2;
1461425bb815Sopenharmony_ci
1462425bb815Sopenharmony_ci  while (lit_idx <= (num_of_literals - 2) / 2)
1463425bb815Sopenharmony_ci  {
1464425bb815Sopenharmony_ci    jerry_save_literals_down_heap (literals, num_of_literals, lit_idx--);
1465425bb815Sopenharmony_ci  }
1466425bb815Sopenharmony_ci
1467425bb815Sopenharmony_ci  for (lit_idx = 0; lit_idx < num_of_literals; lit_idx++)
1468425bb815Sopenharmony_ci  {
1469425bb815Sopenharmony_ci    const lit_utf8_size_t last_idx = num_of_literals - lit_idx - 1;
1470425bb815Sopenharmony_ci
1471425bb815Sopenharmony_ci    ecma_string_t *tmp_str_p = literals[last_idx];
1472425bb815Sopenharmony_ci    literals[last_idx] = literals[0];
1473425bb815Sopenharmony_ci    literals[0] = tmp_str_p;
1474425bb815Sopenharmony_ci
1475425bb815Sopenharmony_ci    jerry_save_literals_down_heap (literals, last_idx, 0);
1476425bb815Sopenharmony_ci  }
1477425bb815Sopenharmony_ci} /* jerry_save_literals_sort */
1478425bb815Sopenharmony_ci
1479425bb815Sopenharmony_ci/**
1480425bb815Sopenharmony_ci * Append characters to the specified buffer.
1481425bb815Sopenharmony_ci *
1482425bb815Sopenharmony_ci * @return the position of the buffer pointer after copy.
1483425bb815Sopenharmony_ci */
1484425bb815Sopenharmony_cistatic uint8_t *
1485425bb815Sopenharmony_cijerry_append_chars_to_buffer (uint8_t *buffer_p, /**< buffer */
1486425bb815Sopenharmony_ci                              uint8_t *buffer_end_p, /**< the end of the buffer */
1487425bb815Sopenharmony_ci                              const char *chars, /**< string */
1488425bb815Sopenharmony_ci                              lit_utf8_size_t string_size) /**< string size */
1489425bb815Sopenharmony_ci{
1490425bb815Sopenharmony_ci  if (buffer_p > buffer_end_p)
1491425bb815Sopenharmony_ci  {
1492425bb815Sopenharmony_ci    return buffer_p;
1493425bb815Sopenharmony_ci  }
1494425bb815Sopenharmony_ci
1495425bb815Sopenharmony_ci  if (string_size == 0)
1496425bb815Sopenharmony_ci  {
1497425bb815Sopenharmony_ci    string_size = (lit_utf8_size_t) strlen (chars);
1498425bb815Sopenharmony_ci  }
1499425bb815Sopenharmony_ci
1500425bb815Sopenharmony_ci  if (buffer_p + string_size <= buffer_end_p)
1501425bb815Sopenharmony_ci  {
1502425bb815Sopenharmony_ci    memcpy ((char *) buffer_p, chars, string_size);
1503425bb815Sopenharmony_ci
1504425bb815Sopenharmony_ci    return buffer_p + string_size;
1505425bb815Sopenharmony_ci  }
1506425bb815Sopenharmony_ci
1507425bb815Sopenharmony_ci  /* Move the pointer behind the buffer to prevent further writes. */
1508425bb815Sopenharmony_ci  return buffer_end_p + 1;
1509425bb815Sopenharmony_ci} /* jerry_append_chars_to_buffer */
1510425bb815Sopenharmony_ci
1511425bb815Sopenharmony_ci/**
1512425bb815Sopenharmony_ci * Append an ecma-string to the specified buffer.
1513425bb815Sopenharmony_ci *
1514425bb815Sopenharmony_ci * @return the position of the buffer pointer after copy.
1515425bb815Sopenharmony_ci */
1516425bb815Sopenharmony_cistatic uint8_t *
1517425bb815Sopenharmony_cijerry_append_ecma_string_to_buffer (uint8_t *buffer_p, /**< buffer */
1518425bb815Sopenharmony_ci                                    uint8_t *buffer_end_p, /**< the end of the buffer */
1519425bb815Sopenharmony_ci                                    ecma_string_t *string_p) /**< ecma-string */
1520425bb815Sopenharmony_ci{
1521425bb815Sopenharmony_ci  ECMA_STRING_TO_UTF8_STRING (string_p, str_buffer_p, str_buffer_size);
1522425bb815Sopenharmony_ci
1523425bb815Sopenharmony_ci  /* Append the string to the buffer. */
1524425bb815Sopenharmony_ci  uint8_t *new_buffer_p = jerry_append_chars_to_buffer (buffer_p,
1525425bb815Sopenharmony_ci                                                        buffer_end_p,
1526425bb815Sopenharmony_ci                                                        (const char *) str_buffer_p,
1527425bb815Sopenharmony_ci                                                        str_buffer_size);
1528425bb815Sopenharmony_ci
1529425bb815Sopenharmony_ci  ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size);
1530425bb815Sopenharmony_ci
1531425bb815Sopenharmony_ci  return new_buffer_p;
1532425bb815Sopenharmony_ci} /* jerry_append_ecma_string_to_buffer */
1533425bb815Sopenharmony_ci
1534425bb815Sopenharmony_ci/**
1535425bb815Sopenharmony_ci * Append an unsigned number to the specified buffer.
1536425bb815Sopenharmony_ci *
1537425bb815Sopenharmony_ci * @return the position of the buffer pointer after copy.
1538425bb815Sopenharmony_ci */
1539425bb815Sopenharmony_cistatic uint8_t *
1540425bb815Sopenharmony_cijerry_append_number_to_buffer (uint8_t *buffer_p, /**< buffer */
1541425bb815Sopenharmony_ci                               uint8_t *buffer_end_p, /**< the end of the buffer */
1542425bb815Sopenharmony_ci                               lit_utf8_size_t number) /**< number */
1543425bb815Sopenharmony_ci{
1544425bb815Sopenharmony_ci  lit_utf8_byte_t uint32_to_str_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
1545425bb815Sopenharmony_ci  lit_utf8_size_t utf8_str_size = ecma_uint32_to_utf8_string (number,
1546425bb815Sopenharmony_ci                                                              uint32_to_str_buffer,
1547425bb815Sopenharmony_ci                                                              ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1548425bb815Sopenharmony_ci
1549425bb815Sopenharmony_ci  JERRY_ASSERT (utf8_str_size <= ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1550425bb815Sopenharmony_ci
1551425bb815Sopenharmony_ci  return jerry_append_chars_to_buffer (buffer_p,
1552425bb815Sopenharmony_ci                                       buffer_end_p,
1553425bb815Sopenharmony_ci                                       (const char *) uint32_to_str_buffer,
1554425bb815Sopenharmony_ci                                       utf8_str_size);
1555425bb815Sopenharmony_ci} /* jerry_append_number_to_buffer */
1556425bb815Sopenharmony_ci
1557425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1558425bb815Sopenharmony_ci
1559425bb815Sopenharmony_ci/**
1560425bb815Sopenharmony_ci * Get the literals from a snapshot. Copies certain string literals into the given
1561425bb815Sopenharmony_ci * buffer in a specified format.
1562425bb815Sopenharmony_ci *
1563425bb815Sopenharmony_ci * Note:
1564425bb815Sopenharmony_ci *      Only valid identifiers are saved in C format.
1565425bb815Sopenharmony_ci *
1566425bb815Sopenharmony_ci * @return size of the literal-list in bytes, at most equal to the buffer size,
1567425bb815Sopenharmony_ci *         if the list of the literals isn't empty,
1568425bb815Sopenharmony_ci *         0 - otherwise.
1569425bb815Sopenharmony_ci */
1570425bb815Sopenharmony_cisize_t
1571425bb815Sopenharmony_cijerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapshot buffer */
1572425bb815Sopenharmony_ci                                  size_t snapshot_size, /**< size of the input snapshot buffer */
1573425bb815Sopenharmony_ci                                  jerry_char_t *lit_buf_p, /**< [out] buffer to save literals to */
1574425bb815Sopenharmony_ci                                  size_t lit_buf_size, /**< the buffer's size */
1575425bb815Sopenharmony_ci                                  bool is_c_format) /**< format-flag */
1576425bb815Sopenharmony_ci{
1577425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
1578425bb815Sopenharmony_ci  const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
1579425bb815Sopenharmony_ci  const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
1580425bb815Sopenharmony_ci
1581425bb815Sopenharmony_ci  if (snapshot_size <= sizeof (jerry_snapshot_header_t)
1582425bb815Sopenharmony_ci      || header_p->magic != JERRY_SNAPSHOT_MAGIC
1583425bb815Sopenharmony_ci      || header_p->version != JERRY_SNAPSHOT_VERSION
1584425bb815Sopenharmony_ci      || !snapshot_check_global_flags (header_p->global_flags))
1585425bb815Sopenharmony_ci  {
1586425bb815Sopenharmony_ci    /* Invalid snapshot format */
1587425bb815Sopenharmony_ci    return 0;
1588425bb815Sopenharmony_ci  }
1589425bb815Sopenharmony_ci
1590425bb815Sopenharmony_ci  JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
1591425bb815Sopenharmony_ci  const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
1592425bb815Sopenharmony_ci
1593425bb815Sopenharmony_ci  ecma_collection_t *lit_pool_p = ecma_new_collection ();
1594425bb815Sopenharmony_ci  scan_snapshot_functions (snapshot_data_p + header_p->func_offsets[0],
1595425bb815Sopenharmony_ci                           literal_base_p,
1596425bb815Sopenharmony_ci                           lit_pool_p,
1597425bb815Sopenharmony_ci                           literal_base_p);
1598425bb815Sopenharmony_ci
1599425bb815Sopenharmony_ci  lit_utf8_size_t literal_count = 0;
1600425bb815Sopenharmony_ci  ecma_value_t *buffer_p = lit_pool_p->buffer_p;
1601425bb815Sopenharmony_ci
1602425bb815Sopenharmony_ci  /* Count the valid and non-magic identifiers in the list. */
1603425bb815Sopenharmony_ci  for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
1604425bb815Sopenharmony_ci  {
1605425bb815Sopenharmony_ci    if (ecma_is_value_string (buffer_p[i]))
1606425bb815Sopenharmony_ci    {
1607425bb815Sopenharmony_ci      ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]);
1608425bb815Sopenharmony_ci
1609425bb815Sopenharmony_ci      if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT)
1610425bb815Sopenharmony_ci      {
1611425bb815Sopenharmony_ci        literal_count++;
1612425bb815Sopenharmony_ci      }
1613425bb815Sopenharmony_ci    }
1614425bb815Sopenharmony_ci  }
1615425bb815Sopenharmony_ci
1616425bb815Sopenharmony_ci  if (literal_count == 0)
1617425bb815Sopenharmony_ci  {
1618425bb815Sopenharmony_ci    ecma_collection_destroy (lit_pool_p);
1619425bb815Sopenharmony_ci    return 0;
1620425bb815Sopenharmony_ci  }
1621425bb815Sopenharmony_ci
1622425bb815Sopenharmony_ci  jerry_char_t *const buffer_start_p = lit_buf_p;
1623425bb815Sopenharmony_ci  jerry_char_t *const buffer_end_p = lit_buf_p + lit_buf_size;
1624425bb815Sopenharmony_ci
1625425bb815Sopenharmony_ci  JMEM_DEFINE_LOCAL_ARRAY (literal_array, literal_count, ecma_string_t *);
1626425bb815Sopenharmony_ci  lit_utf8_size_t literal_idx = 0;
1627425bb815Sopenharmony_ci
1628425bb815Sopenharmony_ci  buffer_p = lit_pool_p->buffer_p;
1629425bb815Sopenharmony_ci
1630425bb815Sopenharmony_ci  /* Count the valid and non-magic identifiers in the list. */
1631425bb815Sopenharmony_ci  for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
1632425bb815Sopenharmony_ci  {
1633425bb815Sopenharmony_ci    if (ecma_is_value_string (buffer_p[i]))
1634425bb815Sopenharmony_ci    {
1635425bb815Sopenharmony_ci      ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]);
1636425bb815Sopenharmony_ci
1637425bb815Sopenharmony_ci      if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT)
1638425bb815Sopenharmony_ci      {
1639425bb815Sopenharmony_ci        literal_array[literal_idx++] = literal_p;
1640425bb815Sopenharmony_ci      }
1641425bb815Sopenharmony_ci    }
1642425bb815Sopenharmony_ci  }
1643425bb815Sopenharmony_ci
1644425bb815Sopenharmony_ci  ecma_collection_destroy (lit_pool_p);
1645425bb815Sopenharmony_ci
1646425bb815Sopenharmony_ci  /* Sort the strings by size at first, then lexicographically. */
1647425bb815Sopenharmony_ci  jerry_save_literals_sort (literal_array, literal_count);
1648425bb815Sopenharmony_ci
1649425bb815Sopenharmony_ci  if (is_c_format)
1650425bb815Sopenharmony_ci  {
1651425bb815Sopenharmony_ci    /* Save literal count. */
1652425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1653425bb815Sopenharmony_ci                                              buffer_end_p,
1654425bb815Sopenharmony_ci                                              "jerry_length_t literal_count = ",
1655425bb815Sopenharmony_ci                                              0);
1656425bb815Sopenharmony_ci
1657425bb815Sopenharmony_ci    lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1658425bb815Sopenharmony_ci
1659425bb815Sopenharmony_ci    /* Save the array of literals. */
1660425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1661425bb815Sopenharmony_ci                                              buffer_end_p,
1662425bb815Sopenharmony_ci                                              ";\n\njerry_char_t *literals[",
1663425bb815Sopenharmony_ci                                              0);
1664425bb815Sopenharmony_ci
1665425bb815Sopenharmony_ci    lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1666425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
1667425bb815Sopenharmony_ci
1668425bb815Sopenharmony_ci    for (lit_utf8_size_t i = 0; i < literal_count; i++)
1669425bb815Sopenharmony_ci    {
1670425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "  \"", 0);
1671425bb815Sopenharmony_ci      ECMA_STRING_TO_UTF8_STRING (literal_array[i], str_buffer_p, str_buffer_size);
1672425bb815Sopenharmony_ci      for (lit_utf8_size_t j = 0; j < str_buffer_size; j++)
1673425bb815Sopenharmony_ci      {
1674425bb815Sopenharmony_ci        uint8_t byte = str_buffer_p[j];
1675425bb815Sopenharmony_ci        if (byte < 32 || byte > 127)
1676425bb815Sopenharmony_ci        {
1677425bb815Sopenharmony_ci          lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\\x", 0);
1678425bb815Sopenharmony_ci          ecma_char_t hex_digit = (ecma_char_t) (byte >> 4);
1679425bb815Sopenharmony_ci          *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0'));
1680425bb815Sopenharmony_ci          hex_digit = (lit_utf8_byte_t) (byte & 0xf);
1681425bb815Sopenharmony_ci          *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0'));
1682425bb815Sopenharmony_ci        }
1683425bb815Sopenharmony_ci        else
1684425bb815Sopenharmony_ci        {
1685425bb815Sopenharmony_ci          if (byte == '\\' || byte == '"')
1686425bb815Sopenharmony_ci          {
1687425bb815Sopenharmony_ci            *lit_buf_p++ = '\\';
1688425bb815Sopenharmony_ci          }
1689425bb815Sopenharmony_ci          *lit_buf_p++ = byte;
1690425bb815Sopenharmony_ci        }
1691425bb815Sopenharmony_ci      }
1692425bb815Sopenharmony_ci
1693425bb815Sopenharmony_ci      ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size);
1694425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\"", 0);
1695425bb815Sopenharmony_ci
1696425bb815Sopenharmony_ci      if (i < literal_count - 1)
1697425bb815Sopenharmony_ci      {
1698425bb815Sopenharmony_ci        lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
1699425bb815Sopenharmony_ci      }
1700425bb815Sopenharmony_ci
1701425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
1702425bb815Sopenharmony_ci    }
1703425bb815Sopenharmony_ci
1704425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1705425bb815Sopenharmony_ci                                              buffer_end_p,
1706425bb815Sopenharmony_ci                                              "};\n\njerry_length_t literal_sizes[",
1707425bb815Sopenharmony_ci                                              0);
1708425bb815Sopenharmony_ci
1709425bb815Sopenharmony_ci    lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1710425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
1711425bb815Sopenharmony_ci  }
1712425bb815Sopenharmony_ci
1713425bb815Sopenharmony_ci  /* Save the literal sizes respectively. */
1714425bb815Sopenharmony_ci  for (lit_utf8_size_t i = 0; i < literal_count; i++)
1715425bb815Sopenharmony_ci  {
1716425bb815Sopenharmony_ci    lit_utf8_size_t str_size = ecma_string_get_size (literal_array[i]);
1717425bb815Sopenharmony_ci
1718425bb815Sopenharmony_ci    if (is_c_format)
1719425bb815Sopenharmony_ci    {
1720425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "  ", 0);
1721425bb815Sopenharmony_ci    }
1722425bb815Sopenharmony_ci
1723425bb815Sopenharmony_ci    lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, str_size);
1724425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0);
1725425bb815Sopenharmony_ci
1726425bb815Sopenharmony_ci    if (is_c_format)
1727425bb815Sopenharmony_ci    {
1728425bb815Sopenharmony_ci      /* Show the given string as a comment. */
1729425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "/* ", 0);
1730425bb815Sopenharmony_ci      lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
1731425bb815Sopenharmony_ci      lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " */", 0);
1732425bb815Sopenharmony_ci
1733425bb815Sopenharmony_ci      if (i < literal_count - 1)
1734425bb815Sopenharmony_ci      {
1735425bb815Sopenharmony_ci        lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
1736425bb815Sopenharmony_ci      }
1737425bb815Sopenharmony_ci    }
1738425bb815Sopenharmony_ci    else
1739425bb815Sopenharmony_ci    {
1740425bb815Sopenharmony_ci      lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
1741425bb815Sopenharmony_ci    }
1742425bb815Sopenharmony_ci
1743425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
1744425bb815Sopenharmony_ci  }
1745425bb815Sopenharmony_ci
1746425bb815Sopenharmony_ci  if (is_c_format)
1747425bb815Sopenharmony_ci  {
1748425bb815Sopenharmony_ci    lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "};\n", 0);
1749425bb815Sopenharmony_ci  }
1750425bb815Sopenharmony_ci
1751425bb815Sopenharmony_ci  JMEM_FINALIZE_LOCAL_ARRAY (literal_array);
1752425bb815Sopenharmony_ci
1753425bb815Sopenharmony_ci  return lit_buf_p <= buffer_end_p ? (size_t) (lit_buf_p - buffer_start_p) : 0;
1754425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1755425bb815Sopenharmony_ci  JERRY_UNUSED (snapshot_p);
1756425bb815Sopenharmony_ci  JERRY_UNUSED (snapshot_size);
1757425bb815Sopenharmony_ci  JERRY_UNUSED (lit_buf_p);
1758425bb815Sopenharmony_ci  JERRY_UNUSED (lit_buf_size);
1759425bb815Sopenharmony_ci  JERRY_UNUSED (is_c_format);
1760425bb815Sopenharmony_ci
1761425bb815Sopenharmony_ci  return 0;
1762425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1763425bb815Sopenharmony_ci} /* jerry_get_literals_from_snapshot */
1764425bb815Sopenharmony_ci
1765425bb815Sopenharmony_ci/**
1766425bb815Sopenharmony_ci * Generate snapshot function from specified source and arguments
1767425bb815Sopenharmony_ci *
1768425bb815Sopenharmony_ci * @return size of snapshot (a number value), if it was generated succesfully
1769425bb815Sopenharmony_ci *          (i.e. there are no syntax errors in source code, buffer size is sufficient,
1770425bb815Sopenharmony_ci *           and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
1771425bb815Sopenharmony_ci *         error object otherwise
1772425bb815Sopenharmony_ci */
1773425bb815Sopenharmony_cijerry_value_t
1774425bb815Sopenharmony_cijerry_generate_function_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */
1775425bb815Sopenharmony_ci                                  size_t resource_name_length, /**< script resource name length */
1776425bb815Sopenharmony_ci                                  const jerry_char_t *source_p, /**< script source */
1777425bb815Sopenharmony_ci                                  size_t source_size, /**< script source size */
1778425bb815Sopenharmony_ci                                  const jerry_char_t *args_p, /**< arguments string */
1779425bb815Sopenharmony_ci                                  size_t args_size, /**< arguments string size */
1780425bb815Sopenharmony_ci                                  uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
1781425bb815Sopenharmony_ci                                  uint32_t *buffer_p, /**< buffer to save snapshot to */
1782425bb815Sopenharmony_ci                                  size_t buffer_size) /**< the buffer's size */
1783425bb815Sopenharmony_ci{
1784425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_SAVE)
1785425bb815Sopenharmony_ci  uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT);
1786425bb815Sopenharmony_ci
1787425bb815Sopenharmony_ci  if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
1788425bb815Sopenharmony_ci  {
1789425bb815Sopenharmony_ci    const char * const error_message_p = "Unsupported generate snapshot flags specified.";
1790425bb815Sopenharmony_ci    return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
1791425bb815Sopenharmony_ci  }
1792425bb815Sopenharmony_ci
1793425bb815Sopenharmony_ci  return jerry_generate_snapshot_with_args (resource_name_p,
1794425bb815Sopenharmony_ci                                            resource_name_length,
1795425bb815Sopenharmony_ci                                            source_p,
1796425bb815Sopenharmony_ci                                            source_size,
1797425bb815Sopenharmony_ci                                            args_p,
1798425bb815Sopenharmony_ci                                            args_size,
1799425bb815Sopenharmony_ci                                            generate_snapshot_opts,
1800425bb815Sopenharmony_ci                                            buffer_p,
1801425bb815Sopenharmony_ci                                            buffer_size);
1802425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1803425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_p);
1804425bb815Sopenharmony_ci  JERRY_UNUSED (resource_name_length);
1805425bb815Sopenharmony_ci  JERRY_UNUSED (source_p);
1806425bb815Sopenharmony_ci  JERRY_UNUSED (source_size);
1807425bb815Sopenharmony_ci  JERRY_UNUSED (args_p);
1808425bb815Sopenharmony_ci  JERRY_UNUSED (args_size);
1809425bb815Sopenharmony_ci  JERRY_UNUSED (generate_snapshot_opts);
1810425bb815Sopenharmony_ci  JERRY_UNUSED (buffer_p);
1811425bb815Sopenharmony_ci  JERRY_UNUSED (buffer_size);
1812425bb815Sopenharmony_ci
1813425bb815Sopenharmony_ci  return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot save is not supported.");
1814425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1815425bb815Sopenharmony_ci} /* jerry_generate_function_snapshot */
1816425bb815Sopenharmony_ci
1817425bb815Sopenharmony_ci/**
1818425bb815Sopenharmony_ci * Load function from specified snapshot buffer
1819425bb815Sopenharmony_ci *
1820425bb815Sopenharmony_ci * Note:
1821425bb815Sopenharmony_ci *      returned value must be freed with jerry_release_value, when it is no longer needed.
1822425bb815Sopenharmony_ci *
1823425bb815Sopenharmony_ci * @return result of bytecode - if run was successful
1824425bb815Sopenharmony_ci *         thrown error - otherwise
1825425bb815Sopenharmony_ci */
1826425bb815Sopenharmony_cijerry_value_t
1827425bb815Sopenharmony_cijerry_load_function_snapshot (const uint32_t *function_snapshot_p, /**< snapshot of the function(s) */
1828425bb815Sopenharmony_ci                              const size_t function_snapshot_size, /**< size of the snapshot */
1829425bb815Sopenharmony_ci                              size_t func_index, /**< index of the function to load */
1830425bb815Sopenharmony_ci                              uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */
1831425bb815Sopenharmony_ci{
1832425bb815Sopenharmony_ci#if ENABLED (JERRY_SNAPSHOT_EXEC)
1833425bb815Sopenharmony_ci  return jerry_snapshot_result (function_snapshot_p, function_snapshot_size, func_index, exec_snapshot_opts, true);
1834425bb815Sopenharmony_ci#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
1835425bb815Sopenharmony_ci  JERRY_UNUSED (function_snapshot_p);
1836425bb815Sopenharmony_ci  JERRY_UNUSED (function_snapshot_size);
1837425bb815Sopenharmony_ci  JERRY_UNUSED (func_index);
1838425bb815Sopenharmony_ci  JERRY_UNUSED (exec_snapshot_opts);
1839425bb815Sopenharmony_ci
1840425bb815Sopenharmony_ci  return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot execution is not supported.");
1841425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1842425bb815Sopenharmony_ci} /* jerry_load_function_snapshot */
1843