1425bb815Sopenharmony_ci/*
2425bb815Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
3425bb815Sopenharmony_ci * Description: improve heap dump.
4425bb815Sopenharmony_ci * Create: 2020/11/20
5425bb815Sopenharmony_ci */
6425bb815Sopenharmony_ci
7425bb815Sopenharmony_ci#include "heapdump.h"
8425bb815Sopenharmony_ci
9425bb815Sopenharmony_ci#include "ecma-builtins.h"
10425bb815Sopenharmony_ci#include "ecma-conversion.h"
11425bb815Sopenharmony_ci#include "ecma-gc.h"
12425bb815Sopenharmony_ci#include "ecma-globals.h"
13425bb815Sopenharmony_ci#include "ecma-helpers.h"
14425bb815Sopenharmony_ci#include "ecma-property-hashmap.h"
15425bb815Sopenharmony_ci#include "ecma-array-object.h"
16425bb815Sopenharmony_ci
17425bb815Sopenharmony_ci#include <stdio.h>
18425bb815Sopenharmony_ci
19425bb815Sopenharmony_cibool gHeapdumpTracing = false;
20425bb815Sopenharmony_ciFILE* gLogHeapdumpFile = NULL;
21425bb815Sopenharmony_cibool GetHeapdumpTracing(void)
22425bb815Sopenharmony_ci{
23425bb815Sopenharmony_ci  return gHeapdumpTracing;
24425bb815Sopenharmony_ci}
25425bb815Sopenharmony_ci
26425bb815Sopenharmony_civoid SetHeapdumpTraring(bool flag)
27425bb815Sopenharmony_ci{
28425bb815Sopenharmony_ci  gHeapdumpTracing = flag;
29425bb815Sopenharmony_ci}
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ciFILE* GetHeapdumpFile(void)
32425bb815Sopenharmony_ci{
33425bb815Sopenharmony_ci  return gLogHeapdumpFile;
34425bb815Sopenharmony_ci}
35425bb815Sopenharmony_ci
36425bb815Sopenharmony_civoid LogHeapdumpInit(const char* filepath)
37425bb815Sopenharmony_ci{
38425bb815Sopenharmony_ci  gLogHeapdumpFile = fopen(filepath, "w+");
39425bb815Sopenharmony_ci}
40425bb815Sopenharmony_ci
41425bb815Sopenharmony_civoid LogHeapdumpClose(void)
42425bb815Sopenharmony_ci{
43425bb815Sopenharmony_ci  fclose(gLogHeapdumpFile);
44425bb815Sopenharmony_ci}
45425bb815Sopenharmony_ci
46425bb815Sopenharmony_cistatic void StartList(void)
47425bb815Sopenharmony_ci{
48425bb815Sopenharmony_ci  LogHeapdump("[\n");
49425bb815Sopenharmony_ci}
50425bb815Sopenharmony_ci
51425bb815Sopenharmony_cistatic void EndList(void)
52425bb815Sopenharmony_ci{
53425bb815Sopenharmony_ci  LogHeapdump("]\n");
54425bb815Sopenharmony_ci}
55425bb815Sopenharmony_ci
56425bb815Sopenharmony_cistatic void Start(void)
57425bb815Sopenharmony_ci{
58425bb815Sopenharmony_ci  LogHeapdump("{\n");
59425bb815Sopenharmony_ci}
60425bb815Sopenharmony_ci
61425bb815Sopenharmony_cistatic void End(void)
62425bb815Sopenharmony_ci{
63425bb815Sopenharmony_ci  LogHeapdump("}\n");
64425bb815Sopenharmony_ci}
65425bb815Sopenharmony_ci
66425bb815Sopenharmony_cistatic void Next(void)
67425bb815Sopenharmony_ci{
68425bb815Sopenharmony_ci  LogHeapdump(",\n");
69425bb815Sopenharmony_ci}
70425bb815Sopenharmony_ci
71425bb815Sopenharmony_cistatic void LogStr(const char* str)
72425bb815Sopenharmony_ci{
73425bb815Sopenharmony_ci  LogHeapdump("\"%s\"\n", str);
74425bb815Sopenharmony_ci}
75425bb815Sopenharmony_ci
76425bb815Sopenharmony_cistatic void LogAddr(void* addr)
77425bb815Sopenharmony_ci{
78425bb815Sopenharmony_ci  LogHeapdump("\"%p\"\n", addr);
79425bb815Sopenharmony_ci}
80425bb815Sopenharmony_ci
81425bb815Sopenharmony_cistatic void LogUint(unsigned int val)
82425bb815Sopenharmony_ci{
83425bb815Sopenharmony_ci  LogHeapdump("%u\n", val);
84425bb815Sopenharmony_ci}
85425bb815Sopenharmony_ci
86425bb815Sopenharmony_cistatic void LogStrObj(const ecma_string_t* obj)
87425bb815Sopenharmony_ci{
88425bb815Sopenharmony_ci  ECMA_STRING_TO_UTF8_STRING(obj, str, str_size);
89425bb815Sopenharmony_ci  LogHeapdump("\"");
90425bb815Sopenharmony_ci  for (int ii = 0; ii < (int)str_size; ++ii) {
91425bb815Sopenharmony_ci    LogHeapdump("%c", str[ii]);
92425bb815Sopenharmony_ci  }
93425bb815Sopenharmony_ci  LogHeapdump("\"\n");
94425bb815Sopenharmony_ci}
95425bb815Sopenharmony_ci
96425bb815Sopenharmony_cistatic void Key(const char* key)
97425bb815Sopenharmony_ci{
98425bb815Sopenharmony_ci  LogHeapdump("\"%s\"", key);
99425bb815Sopenharmony_ci  LogHeapdump(":\n");
100425bb815Sopenharmony_ci}
101425bb815Sopenharmony_ci
102425bb815Sopenharmony_cistatic void KeyUint(unsigned int key)
103425bb815Sopenharmony_ci{
104425bb815Sopenharmony_ci  LogHeapdump("\"%u\"", key);
105425bb815Sopenharmony_ci  LogHeapdump(":\n");
106425bb815Sopenharmony_ci}
107425bb815Sopenharmony_ci
108425bb815Sopenharmony_cistatic void Type(const char* type)
109425bb815Sopenharmony_ci{
110425bb815Sopenharmony_ci  Key("type");
111425bb815Sopenharmony_ci  LogHeapdump("\"%s\"", type);
112425bb815Sopenharmony_ci  Next();
113425bb815Sopenharmony_ci}
114425bb815Sopenharmony_ci
115425bb815Sopenharmony_cistatic void Addr(void* addr)
116425bb815Sopenharmony_ci{
117425bb815Sopenharmony_ci  Key("addr");
118425bb815Sopenharmony_ci  LogHeapdump("\"%p\"", addr);
119425bb815Sopenharmony_ci  Next();
120425bb815Sopenharmony_ci}
121425bb815Sopenharmony_ci
122425bb815Sopenharmony_civoid DumpInfoLexEnv(const ecma_object_t* object)
123425bb815Sopenharmony_ci{
124425bb815Sopenharmony_ci  Key("outer");
125425bb815Sopenharmony_ci  jmem_cpointer_t outer_lex_env_cp = object->u2.outer_reference_cp;
126425bb815Sopenharmony_ci  if (outer_lex_env_cp != JMEM_CP_NULL) {
127425bb815Sopenharmony_ci    LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, outer_lex_env_cp));
128425bb815Sopenharmony_ci  } else {
129425bb815Sopenharmony_ci    LogAddr(NULL);
130425bb815Sopenharmony_ci  }
131425bb815Sopenharmony_ci  Next();
132425bb815Sopenharmony_ci
133425bb815Sopenharmony_ci  Key("subtype");
134425bb815Sopenharmony_ci  if (ecma_get_lex_env_type(object) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) {
135425bb815Sopenharmony_ci    LogStr("binding");
136425bb815Sopenharmony_ci    Next();
137425bb815Sopenharmony_ci
138425bb815Sopenharmony_ci    Key("binding");
139425bb815Sopenharmony_ci    ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object(object);
140425bb815Sopenharmony_ci    LogAddr(binding_object_p);
141425bb815Sopenharmony_ci  } else {
142425bb815Sopenharmony_ci    LogStr("declarative");
143425bb815Sopenharmony_ci  }
144425bb815Sopenharmony_ci}
145425bb815Sopenharmony_ci
146425bb815Sopenharmony_civoid DumpInfoFunction(const ecma_object_t* object)
147425bb815Sopenharmony_ci{
148425bb815Sopenharmony_ci  Key("is_builtin");
149425bb815Sopenharmony_ci  ecma_extended_object_t* ext_obj = (ecma_extended_object_t*)object;
150425bb815Sopenharmony_ci  if (ecma_get_object_is_builtin (object)) {
151425bb815Sopenharmony_ci    LogStr("true");
152425bb815Sopenharmony_ci    Next();
153425bb815Sopenharmony_ci
154425bb815Sopenharmony_ci    Key("is_routine");
155425bb815Sopenharmony_ci    if (ecma_builtin_function_is_routine ((ecma_object_t*)object)) {
156425bb815Sopenharmony_ci      LogStr("true");
157425bb815Sopenharmony_ci    } else {
158425bb815Sopenharmony_ci      LogStr("true");
159425bb815Sopenharmony_ci    }
160425bb815Sopenharmony_ci    Next();
161425bb815Sopenharmony_ci
162425bb815Sopenharmony_ci    Key("id");
163425bb815Sopenharmony_ci    LogUint(ext_obj->u.built_in.id);
164425bb815Sopenharmony_ci    Next();
165425bb815Sopenharmony_ci    Key("routine_id");
166425bb815Sopenharmony_ci    LogUint(ext_obj->u.built_in.routine_id);
167425bb815Sopenharmony_ci  } else {
168425bb815Sopenharmony_ci    LogStr("false");
169425bb815Sopenharmony_ci    Next();
170425bb815Sopenharmony_ci
171425bb815Sopenharmony_ci    Key("scope");
172425bb815Sopenharmony_ci    LogAddr(ECMA_GET_INTERNAL_VALUE_POINTER(ecma_object_t, ext_obj->u.function.scope_cp));
173425bb815Sopenharmony_ci  }
174425bb815Sopenharmony_ci}
175425bb815Sopenharmony_ci
176425bb815Sopenharmony_civoid DumpPropertyPair(ecma_property_pair_t* pair)
177425bb815Sopenharmony_ci{
178425bb815Sopenharmony_ci  ecma_property_header_t* header = (ecma_property_header_t*)pair;
179425bb815Sopenharmony_ci  for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) {
180425bb815Sopenharmony_ci    Start();
181425bb815Sopenharmony_ci
182425bb815Sopenharmony_ci    switch (ECMA_PROPERTY_GET_TYPE(header->types[i])) {
183425bb815Sopenharmony_ci      case ECMA_PROPERTY_TYPE_NAMEDDATA: {
184425bb815Sopenharmony_ci        Type("data");
185425bb815Sopenharmony_ci
186425bb815Sopenharmony_ci        Key("key");
187425bb815Sopenharmony_ci        ecma_string_t* key_str = ecma_string_from_property_name(header->types[i],
188425bb815Sopenharmony_ci                                                                pair->names_cp[i]);
189425bb815Sopenharmony_ci        LogStrObj(key_str);
190425bb815Sopenharmony_ci        ecma_deref_ecma_string(key_str);
191425bb815Sopenharmony_ci        Next();
192425bb815Sopenharmony_ci
193425bb815Sopenharmony_ci        Key("value");
194425bb815Sopenharmony_ci        ecma_value_t value = pair->values[i].value;
195425bb815Sopenharmony_ci        if (ecma_is_value_object(value)) {
196425bb815Sopenharmony_ci          ecma_object_t* value_obj = ecma_get_object_from_value(value);
197425bb815Sopenharmony_ci          LogAddr(value_obj);
198425bb815Sopenharmony_ci        } else {
199425bb815Sopenharmony_ci          ecma_string_t* value_str = ecma_op_to_string(value);
200425bb815Sopenharmony_ci          LogStrObj(value_str);
201425bb815Sopenharmony_ci        }
202425bb815Sopenharmony_ci        break;
203425bb815Sopenharmony_ci      }
204425bb815Sopenharmony_ci      case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: {
205425bb815Sopenharmony_ci        Type("accessor");
206425bb815Sopenharmony_ci
207425bb815Sopenharmony_ci        ecma_property_value_t* accessor_objs_p = pair->values + i;
208425bb815Sopenharmony_ci        ecma_getter_setter_pointers_t* get_set_pair_p =
209425bb815Sopenharmony_ci            ecma_get_named_accessor_property(accessor_objs_p);
210425bb815Sopenharmony_ci
211425bb815Sopenharmony_ci        Key("getter");
212425bb815Sopenharmony_ci        if (get_set_pair_p->getter_cp != JMEM_CP_NULL) {
213425bb815Sopenharmony_ci          LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->getter_cp));
214425bb815Sopenharmony_ci        } else {
215425bb815Sopenharmony_ci          LogAddr(NULL);
216425bb815Sopenharmony_ci        }
217425bb815Sopenharmony_ci        Next();
218425bb815Sopenharmony_ci
219425bb815Sopenharmony_ci        Key("setter");
220425bb815Sopenharmony_ci        if (get_set_pair_p->setter_cp != JMEM_CP_NULL) {
221425bb815Sopenharmony_ci          LogAddr(ECMA_GET_NON_NULL_POINTER(ecma_object_t, get_set_pair_p->setter_cp));
222425bb815Sopenharmony_ci        } else {
223425bb815Sopenharmony_ci          LogAddr(NULL);
224425bb815Sopenharmony_ci        }
225425bb815Sopenharmony_ci        break;
226425bb815Sopenharmony_ci      }
227425bb815Sopenharmony_ci      case ECMA_PROPERTY_TYPE_INTERNAL: {
228425bb815Sopenharmony_ci        Type("internal");
229425bb815Sopenharmony_ci        Key("TODO");
230425bb815Sopenharmony_ci        LogStr("Not implemented yet");
231425bb815Sopenharmony_ci        break;
232425bb815Sopenharmony_ci      }
233425bb815Sopenharmony_ci      default: {
234425bb815Sopenharmony_ci        break;
235425bb815Sopenharmony_ci      }
236425bb815Sopenharmony_ci    }
237425bb815Sopenharmony_ci    End();
238425bb815Sopenharmony_ci    if (i + 1 < ECMA_PROPERTY_PAIR_ITEM_COUNT) {
239425bb815Sopenharmony_ci      Next();
240425bb815Sopenharmony_ci    }
241425bb815Sopenharmony_ci  }
242425bb815Sopenharmony_ci}
243425bb815Sopenharmony_ci
244425bb815Sopenharmony_civoid DumpInfoObject(ecma_object_t* object, heapdump_object_flags_t flags)
245425bb815Sopenharmony_ci{
246425bb815Sopenharmony_ci  Start();
247425bb815Sopenharmony_ci  Addr(object);
248425bb815Sopenharmony_ci  if (flags & HEAPDUMP_OBJECT_ROOT) {
249425bb815Sopenharmony_ci    Key("Root");
250425bb815Sopenharmony_ci    LogStr("true");
251425bb815Sopenharmony_ci    Next();
252425bb815Sopenharmony_ci  }
253425bb815Sopenharmony_ci
254425bb815Sopenharmony_ci  if (flags & HEAPDUMP_OBJECT_GLOBAL) {
255425bb815Sopenharmony_ci    Key("Global");
256425bb815Sopenharmony_ci    LogStr("true");
257425bb815Sopenharmony_ci    Next();
258425bb815Sopenharmony_ci  }
259425bb815Sopenharmony_ci
260425bb815Sopenharmony_ci  Key("RefCount");
261425bb815Sopenharmony_ci  LogUint(object->type_flags_refs >> REF_CNT_SHIFT);
262425bb815Sopenharmony_ci  Next();
263425bb815Sopenharmony_ci
264425bb815Sopenharmony_ci  if (ecma_is_lexical_environment(object)) {
265425bb815Sopenharmony_ci    Type("LexEnv");
266425bb815Sopenharmony_ci    DumpInfoLexEnv(object);
267425bb815Sopenharmony_ci    goto finish;
268425bb815Sopenharmony_ci  } else {
269425bb815Sopenharmony_ci    Key("__proto__");
270425bb815Sopenharmony_ci    jmem_cpointer_t proto_cp = object->u2.prototype_cp;
271425bb815Sopenharmony_ci    if (proto_cp != JMEM_CP_NULL) {
272425bb815Sopenharmony_ci      LogAddr(ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp));
273425bb815Sopenharmony_ci    } else {
274425bb815Sopenharmony_ci      LogAddr(NULL);
275425bb815Sopenharmony_ci    }
276425bb815Sopenharmony_ci    Next();
277425bb815Sopenharmony_ci    switch (ecma_get_object_type(object)) {
278425bb815Sopenharmony_ci      case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: {
279425bb815Sopenharmony_ci        Type("ExternalFunction");
280425bb815Sopenharmony_ci        break;
281425bb815Sopenharmony_ci      }
282425bb815Sopenharmony_ci      case ECMA_OBJECT_TYPE_BOUND_FUNCTION: {
283425bb815Sopenharmony_ci        Type("BoundFunction");
284425bb815Sopenharmony_ci        break;
285425bb815Sopenharmony_ci      }
286425bb815Sopenharmony_ci      case ECMA_OBJECT_TYPE_FUNCTION: {
287425bb815Sopenharmony_ci        Type("Function");
288425bb815Sopenharmony_ci        DumpInfoFunction(object);
289425bb815Sopenharmony_ci        Next();
290425bb815Sopenharmony_ci        break;
291425bb815Sopenharmony_ci      }
292425bb815Sopenharmony_ci      case ECMA_OBJECT_TYPE_PSEUDO_ARRAY: {
293425bb815Sopenharmony_ci        Type("PseudoArray");
294425bb815Sopenharmony_ci        ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object;
295425bb815Sopenharmony_ci        if (ext_object->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS) {
296425bb815Sopenharmony_ci          Key("subtype");
297425bb815Sopenharmony_ci          LogStr("arguments");
298425bb815Sopenharmony_ci          Next();
299425bb815Sopenharmony_ci          ecma_object_t* lex_env = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
300425bb815Sopenharmony_ci              ext_object->u.pseudo_array.u2.lex_env_cp);
301425bb815Sopenharmony_ci          Key("lex_env");
302425bb815Sopenharmony_ci          LogAddr(lex_env);
303425bb815Sopenharmony_ci        } else {
304425bb815Sopenharmony_ci          Key("subtype");
305425bb815Sopenharmony_ci          LogStr("!!! Unknown");
306425bb815Sopenharmony_ci        }
307425bb815Sopenharmony_ci        goto finish;
308425bb815Sopenharmony_ci      }
309425bb815Sopenharmony_ci      case ECMA_OBJECT_TYPE_ARRAY: {
310425bb815Sopenharmony_ci        Type("Array");
311425bb815Sopenharmony_ci        ecma_extended_object_t* ext_object = (ecma_extended_object_t*)object;
312425bb815Sopenharmony_ci
313425bb815Sopenharmony_ci        if (ecma_op_object_is_fast_array(object)) {
314425bb815Sopenharmony_ci          Key("subtype");
315425bb815Sopenharmony_ci          LogStr("fast");
316425bb815Sopenharmony_ci          Next();
317425bb815Sopenharmony_ci
318425bb815Sopenharmony_ci          Key("data");
319425bb815Sopenharmony_ci          Start();
320425bb815Sopenharmony_ci          if (object->u1.property_list_cp != JMEM_CP_NULL) {
321425bb815Sopenharmony_ci            ecma_value_t *values =
322425bb815Sopenharmony_ci                ECMA_GET_NON_NULL_POINTER (ecma_value_t, object->u1.property_list_cp);
323425bb815Sopenharmony_ci            bool skip_comma = true;
324425bb815Sopenharmony_ci            for (uint32_t i = 0; i < ext_object->u.array.length; i++) {
325425bb815Sopenharmony_ci              if (ecma_is_value_array_hole(values[i])) {
326425bb815Sopenharmony_ci                continue;
327425bb815Sopenharmony_ci              }
328425bb815Sopenharmony_ci              if (skip_comma) {
329425bb815Sopenharmony_ci                skip_comma = false;
330425bb815Sopenharmony_ci              } else {
331425bb815Sopenharmony_ci                Next();
332425bb815Sopenharmony_ci              }
333425bb815Sopenharmony_ci              KeyUint(i);
334425bb815Sopenharmony_ci              if (ecma_is_value_object(values[i])) {
335425bb815Sopenharmony_ci                ecma_object_t* value_obj = ecma_get_object_from_value(values[i]);
336425bb815Sopenharmony_ci                LogAddr(value_obj);
337425bb815Sopenharmony_ci              } else {
338425bb815Sopenharmony_ci                ecma_string_t* value_str = ecma_op_to_string(values[i]);
339425bb815Sopenharmony_ci                LogStrObj(value_str);
340425bb815Sopenharmony_ci              }
341425bb815Sopenharmony_ci            }
342425bb815Sopenharmony_ci          }
343425bb815Sopenharmony_ci          End();
344425bb815Sopenharmony_ci          goto finish;
345425bb815Sopenharmony_ci        } else {
346425bb815Sopenharmony_ci          Key("subtype");
347425bb815Sopenharmony_ci          LogStr("sparse");
348425bb815Sopenharmony_ci          Next();
349425bb815Sopenharmony_ci        }
350425bb815Sopenharmony_ci        break;
351425bb815Sopenharmony_ci      }
352425bb815Sopenharmony_ci      default: {
353425bb815Sopenharmony_ci        Type("Object");
354425bb815Sopenharmony_ci        break;
355425bb815Sopenharmony_ci      }
356425bb815Sopenharmony_ci    }
357425bb815Sopenharmony_ci  }
358425bb815Sopenharmony_ci
359425bb815Sopenharmony_ci  jmem_cpointer_t prop_iter_cp = object->u1.property_list_cp;
360425bb815Sopenharmony_ci
361425bb815Sopenharmony_ci#if ENABLED (JERRY_PROPRETY_HASHMAP)
362425bb815Sopenharmony_ci  if (prop_iter_cp != JMEM_CP_NULL) {
363425bb815Sopenharmony_ci    ecma_property_header_t* prop_iter_p =
364425bb815Sopenharmony_ci        ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp);
365425bb815Sopenharmony_ci    if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) {
366425bb815Sopenharmony_ci      prop_iter_cp = prop_iter_p->next_property_cp;
367425bb815Sopenharmony_ci    }
368425bb815Sopenharmony_ci  }
369425bb815Sopenharmony_ci#endif
370425bb815Sopenharmony_ci
371425bb815Sopenharmony_ci  Key("properties");
372425bb815Sopenharmony_ci  StartList();
373425bb815Sopenharmony_ci  while (prop_iter_cp != JMEM_CP_NULL) {
374425bb815Sopenharmony_ci    ecma_property_header_t* prop_iter_p =
375425bb815Sopenharmony_ci        ECMA_GET_NON_NULL_POINTER(ecma_property_header_t, prop_iter_cp);
376425bb815Sopenharmony_ci    DumpPropertyPair((ecma_property_pair_t *) prop_iter_p);
377425bb815Sopenharmony_ci
378425bb815Sopenharmony_ci    prop_iter_cp = prop_iter_p->next_property_cp;
379425bb815Sopenharmony_ci    if (prop_iter_cp != JMEM_CP_NULL) {
380425bb815Sopenharmony_ci      Next();
381425bb815Sopenharmony_ci    }
382425bb815Sopenharmony_ci  }
383425bb815Sopenharmony_ci  EndList();
384425bb815Sopenharmony_ci
385425bb815Sopenharmony_ci finish:
386425bb815Sopenharmony_ci  End();
387425bb815Sopenharmony_ci  Next();
388425bb815Sopenharmony_ci}
389