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_value_free.

  jerry_value_t global = jerry_current_realm ();

  /* The value stored in the 'global' variable contains a live
   * reference to the global object. The system also keeps its
   * own live reference to the global object. These two references
   * are independent, and both must be destroyed before the global
   * object can be freed. */

  jerry_value_free (global);

  /* Without jerry_value_free() the global object will not
   * be freed even by jerry_cleanup(). After the reference
   * is released it becomes a dead reference and cannot be
   * used anymore. */

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

  jerry_value_t pi_ref1 = jerry_number (3.14);
  jerry_value_t pi_ref2 = jerry_value_copy (pi_ref1);

  /* Both pi_ref1 and pi_ref2 refer to the same 3.14 value
   * although they might not be equal in C (pi_ref1 != pi_ref2). */

  /* Both references must be released. */
  jerry_value_free (pi_ref1);
  jerry_value_free (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.

  jerry_value_free (pi_ref1);
  jerry_value_free (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.

  jerry_value_t prop_value = jerry_object_get (...);

  /* The prop_value must be released later because both the base
   * object and the prop_value have an independent reference to
   * the same JavaScript value. When the operation fails, the
   * prop_value contains a live reference to an error object.
   * This reference must be released as well. */

  if (jerry_value_is_exception (prop_value))
  {
    /* Errors can be handled here. */
  }
  else
  {
    /* The application has a live reference to the property
     * value even if the base object is freed by the garbage
     * collector. */
  }

  /* The prop_value must be released. */
  jerry_value_free (prop_value);

  /* Property setting is the same. */

  jerry_value_t new_prop_value = jerry_number (2.718);
  jerry_value_t result = jerry_object_set (..., new_prop_value);

  /* If the property set is successful, a new reference is created
   * for the value referenced by new_prop_value. The new_prop_value
   * reference must be released regardless of whether the operation
   * is successful. */

  /* The new_prop_value can be passed to other JerryScript API
   * functions before the jerry_value_free () call. */

  jerry_value_free (new_prop_value);

  /* The reference stored in the 'result' variable is live whether
   * the operation is successful or not, and must also be freed. */

  if (jerry_value_is_exception (result))
  {
    /* Errors can be handled here. */
  }
  else
  {
    /* A reference to a true primitive value is returned. */
  }

  jerry_value_free (result);

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

  /* There are no 'ifs' in this snippet. */
  jerry_value_free (jerry_object_set (..., new_prop_value));
  jerry_value_free (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.

jerry_value_t my_external_handler (const jerry_value_t function_obj,
                                   const jerry_value_t this_val,
                                   const jerry_value_t args_p[],
                                   const jerry_length_t args_count
{
  /* Do not release function_obj, this_val, and args_p because
   * these references are automatically released after the handler
   * is returned. This approach reduces code size which is useful
   * on embedded systems. However you can create other references
   * to them by calling jerry_value_copy () if needed. */

  /* Since the ownership of the reference is transferred to the
   * caller the following snippet is valid. */

  /* If the value to be returned is needed for other purposes the
   * jerry_value_copy () can be used to create new references. */
  return jerry_string (...);
}

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

  jerry_value_t undef = jerry_undefined ();
  jerry_value_t undef2 = undef;

  /* Releasing either undef or undef2 is valid but not both.
   * After the release both references become dead (invalid). */
  jerry_value_free (undef2);

  /* Dead references can be reassigned again. */
  undef = jerry_boolean (true);

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

  jerry_value_t a = jerry_boolean (true);

  jerry_value_t b = a;
  jerry_value_t c = a;

  /* A new reference is assigned to 'a'. */
  a = jerry_boolean (false);

  [...]

  jerry_value_free (a);
  /* The 'a' (boolean false) reference becomes dead (invalid). */

  jerry_value_free (c);
  /* Both 'b' and 'c' (boolean true) references become dead. */

  /* Since all references are released, no memory leak occurs. */