Reference counting in JerryScript

In JerryScript all jerry_value_t values are independent references to internal objects. Values returned by JerryScript API functions are always live references and must be released by jerry_release_value.

  1. jerry_value_t global = jerry_get_global_object ();
  2. /* The value stored in the 'global' variable contains a live
  3. * reference to the global object. The system also keeps its
  4. * own live reference to the global object. These two references
  5. * are independent, and both must be destroyed before the global
  6. * object can be freed. */
  7. jerry_release_value (global);
  8. /* Without jerry_release_value() the global object will not
  9. * be freed even by jerry_cleanup(). After the reference
  10. * is released it becomes a dead reference and cannot be
  11. * used anymore. */

Multiple references might refer to the same internal object even though their jerry_value_t representation might be different.

  1. jerry_value_t pi_ref1 = jerry_create_number (3.14);
  2. jerry_value_t pi_ref2 = jerry_acquire_value (pi_ref1);
  3. /* Both pi_ref1 and pi_ref2 refer to the same 3.14 value
  4. * although they might not be equal in C (pi_ref1 != pi_ref2). */
  5. /* Both references must be released. */
  6. jerry_release_value (pi_ref1);
  7. jerry_release_value (pi_ref2);

Releasing the same jerry_value_t twice to release two live references is not allowed and it might cause crashes. Hence the following code is an INCORRECT WAY of releasing the 3.14 value.

  1. jerry_release_value (pi_ref1);
  2. jerry_release_value (pi_ref1);

JerryScript API functions returning with a jerry_value_t always return with a new live reference. Passing a jerry_value_t to an API function never releases its reference (unless explicitly stated in the documentation). The next example shows this behaviour through property getting and setting.

  1. jerry_value_t prop_value = jerry_get_property (...);
  2. /* The prop_value must be released later because both the base
  3. * object and the prop_value have an independent reference to
  4. * the same JavaScript value. When the operation fails, the
  5. * prop_value contains a live reference to an error object.
  6. * This reference must be released as well. */
  7. if (jerry_value_is_error (prop_value))
  8. {
  9. /* Errors can be handled here. */
  10. }
  11. else
  12. {
  13. /* The application has a live reference to the property
  14. * value even if the base object is freed by the garbage
  15. * collector. */
  16. }
  17. /* The prop_value must be released. */
  18. jerry_release_value (prop_value);
  19. /* Property setting is the same. */
  20. jerry_value_t new_prop_value = jerry_create_number (2.718);
  21. jerry_value_t result = jerry_set_property (..., new_prop_value);
  22. /* If the property set is successful, a new reference is created
  23. * for the value referenced by new_prop_value. The new_prop_value
  24. * reference must be released regardless of whether the operation
  25. * is successful. */
  26. /* The new_prop_value can be passed to other JerryScript API
  27. * functions before the jerry_release_value () call. */
  28. jerry_release_value (new_prop_value);
  29. /* The reference stored in the 'result' variable is live whether
  30. * the operation is successful or not, and must also be freed. */
  31. if (jerry_value_is_error (result))
  32. {
  33. /* Errors can be handled here. */
  34. }
  35. else
  36. {
  37. /* A reference to a true primitive value is returned. */
  38. }
  39. jerry_release_value (result);

The simplest form of setting a property without error checking is the following:

  1. /* There are no 'ifs' in this snippet. */
  2. jerry_release_value (jerry_set_property (..., new_prop_value));
  3. jerry_release_value (new_prop_value);

The reference returned by a jerry_external_handler_t callback transfers the ownership of the live reference. Otherwise the referenced object could be freed by the garbage collector.

  1. jerry_value_t my_external_handler (const jerry_value_t function_obj,
  2. const jerry_value_t this_val,
  3. const jerry_value_t args_p[],
  4. const jerry_length_t args_count
  5. {
  6. /* Do not release function_obj, this_val, and args_p because
  7. * these references are automatically released after the handler
  8. * is returned. This approach reduces code size which is useful
  9. * on embedded systems. However you can create other references
  10. * to them by calling jerry_acquire_value () if needed. */
  11. /* Since the ownership of the reference is transferred to the
  12. * caller the following snippet is valid. */
  13. /* If the value to be returned is needed for other purposes the
  14. * jerry_acquire_value () can be used to create new references. */
  15. return jerry_create_string (...);
  16. }

Duplicating a jerry_value_t in C does not create another live reference.

  1. jerry_value_t undef = jerry_create_undefined ();
  2. jerry_value_t undef2 = undef;
  3. /* Releasing either undef or undef2 is valid but not both.
  4. * After the release both references become dead (invalid). */
  5. jerry_release_value (undef2);
  6. /* Dead references can be reassigned again. */
  7. undef = jerry_create_boolean (true);

References can be duplicated in C as long as only one of them is freed.

  1. jerry_value_t a = jerry_create_boolean (true);
  2. jerry_value_t b = a;
  3. jerry_value_t c = a;
  4. /* A new reference is assigned to 'a'. */
  5. a = jerry_create_boolean (false);
  6. [...]
  7. jerry_release_value (a);
  8. /* The 'a' (boolean false) reference becomes dead (invalid). */
  9. jerry_release_value (c);
  10. /* Both 'b' and 'c' (boolean true) references become dead. */
  11. /* Since all references are released, no memory leak occurs. */