TPMI_DH_ENTITY_Unmarshal(TPMI_DH_ENTITY *target, BYTE **buffer, INT32 *size, BOOL allowNull)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_DH_ENTITY orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_HANDLE_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	BOOL isNotOwner = *target != TPM_RH_OWNER;
	BOOL isNotEndorsement = *target != TPM_RH_ENDORSEMENT;
	BOOL isNotPlatform = *target != TPM_RH_PLATFORM;
	BOOL isNotLockout = *target != TPM_RH_LOCKOUT;
	BOOL isNotTransient = (*target < TRANSIENT_FIRST) || (*target > TRANSIENT_LAST);
	BOOL isNotPersistent = (*target < PERSISTENT_FIRST) || (*target > PERSISTENT_LAST);
	BOOL isNotNv = (*target < NV_INDEX_FIRST) || (*target > NV_INDEX_LAST);
	BOOL isNotPcr = (*target > PCR_LAST);
	BOOL isNotAuth = (*target < TPM_RH_AUTH_00) || (*target > TPM_RH_AUTH_FF);
	BOOL isNotLegalNull = (*target != TPM_RH_NULL) || !allowNull;
	if (isNotOwner &&
	    isNotEndorsement &&
	    isNotPlatform &&
	    isNotLockout &&
	    isNotTransient &&
	    isNotPersistent &&
	    isNotNv &&
	    isNotPcr &&
	    isNotAuth &&
	    isNotLegalNull) {
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPMI_SH_POLICY_Unmarshal(TPMI_SH_POLICY *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_SH_POLICY orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_HANDLE_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	BOOL isNotPolicySession = (*target < POLICY_SESSION_FIRST) || (*target > POLICY_SESSION_LAST);
	if (isNotPolicySession) {
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPML_TAGGED_TPM_PROPERTY_Unmarshal(TPML_TAGGED_TPM_PROPERTY  *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    UINT32 i;
    if (rc == TPM_RC_SUCCESS) {
	rc = UINT32_Unmarshal(&target->count, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	if (target->count > MAX_TPM_PROPERTIES) {
	    rc = TPM_RC_SIZE;
	    target->count = 0; // libtpms added
	}
    }
    for (i = 0 ; (rc == TPM_RC_SUCCESS) && (i < target->count) ; i++) {
	rc = TPMS_TAGGED_PROPERTY_Unmarshal(&target->tpmProperty[i], buffer, size);
    }
    return rc;
}


TPMI_SM4_KEY_BITS_Unmarshal(TPMI_SM4_KEY_BITS *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_SM4_KEY_BITS orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_KEY_BITS_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	switch (*target) {
	  case 128:
	    break;
	  default:
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPMT_TK_VERIFIED_Unmarshal(TPMT_TK_VERIFIED *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPM_ST orig_tag = target->tag; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_ST_Unmarshal(&target->tag, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	if (target->tag != TPM_ST_VERIFIED) {
	    rc = TPM_RC_TAG;
	    target->tag = orig_tag; // libtpms added
	}
    }
    if (rc == TPM_RC_SUCCESS) {
	rc = TPMI_RH_HIERARCHY_Unmarshal(&target->hierarchy, buffer, size, YES);
    }
    if (rc == TPM_RC_SUCCESS) {
	rc = TPM2B_DIGEST_Unmarshal(&target->digest, buffer, size);
    }
    return rc;
}


TPMS_SCHEME_XOR_Unmarshal(TPMS_SCHEME_XOR *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    if (rc == TPM_RC_SUCCESS) {
	rc = TPMI_ALG_HASH_Unmarshal(&target->hashAlg, buffer, size, NO);	/* as of rev 147 */
    }
    if (rc == TPM_RC_SUCCESS) {
	rc = TPMI_ALG_KDF_Unmarshal(&target->kdf, buffer, size, YES);
    }
    return rc;
}


TPMI_ALG_SIG_SCHEME_Unmarshal(TPMI_ALG_SIG_SCHEME *target, BYTE **buffer, INT32 *size, BOOL allowNull)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_ALG_SIG_SCHEME orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_ALG_ID_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	switch (*target) {
#if ALG_HMAC
	  case TPM_ALG_HMAC:
#endif
#if ALG_RSASSA
	  case TPM_ALG_RSASSA:
#endif
#if ALG_RSAPSS
	  case TPM_ALG_RSAPSS:
#endif
#if ALG_ECDSA
	  case TPM_ALG_ECDSA:
#endif
#if ALG_ECDAA
	  case TPM_ALG_ECDAA:
#endif
#if ALG_SM2
	  case TPM_ALG_SM2:
#endif
#if ALG_ECSCHNORR
	  case TPM_ALG_ECSCHNORR:
#endif
	    break;
	  case TPM_ALG_NULL:
	    if (allowNull) {
		break;
	    }
	  default:
	    rc = TPM_RC_SCHEME;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPMI_RH_PROVISION_Unmarshal(TPMI_RH_PROVISION *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_RH_PROVISION orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_HANDLE_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	switch (*target) {
	  case TPM_RH_OWNER:
	  case TPM_RH_PLATFORM:
	    break;
	  default:
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPMU_SCHEME_KEYEDHASH_Unmarshal(TPMU_SCHEME_KEYEDHASH *target, BYTE **buffer, INT32 *size, UINT32 selector)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    switch (selector) {
#if ALG_HMAC
      case TPM_ALG_HMAC:
	rc = TPMS_SCHEME_HMAC_Unmarshal(&target->hmac, buffer, size);
	break;
#endif
#if ALG_XOR
      case TPM_ALG_XOR:
	rc = TPMS_SCHEME_XOR_Unmarshal(&target->xorr, buffer, size);
	break;
#endif
      case TPM_ALG_NULL:
	break;
      default:
	rc = TPM_RC_SELECTOR;
    }
    return rc;
}


TPMU_SIG_SCHEME_Unmarshal(TPMU_SIG_SCHEME *target, BYTE **buffer, INT32 *size, UINT32 selector)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    switch (selector) {
#if ALG_RSASSA
      case TPM_ALG_RSASSA:
	rc = TPMS_SIG_SCHEME_RSASSA_Unmarshal(&target->rsassa, buffer, size);
	break;
#endif
#if ALG_RSAPSS
      case TPM_ALG_RSAPSS:
	rc = TPMS_SIG_SCHEME_RSAPSS_Unmarshal(&target->rsapss, buffer, size);
	break;
#endif
#if ALG_ECDSA
      case TPM_ALG_ECDSA:
	rc = TPMS_SIG_SCHEME_ECDSA_Unmarshal(&target->ecdsa, buffer, size);
	break;
#endif
#if ALG_ECDAA
      case TPM_ALG_ECDAA:
	rc = TPMS_SIG_SCHEME_ECDAA_Unmarshal(&target->ecdaa, buffer, size);
	break;
#endif
#if ALG_SM2
      case TPM_ALG_SM2:
	rc = TPMS_SIG_SCHEME_SM2_Unmarshal(&target->sm2, buffer, size);
	break;
#endif
#if ALG_ECSCHNORR
      case TPM_ALG_ECSCHNORR:
	rc = TPMS_SIG_SCHEME_ECSCHNORR_Unmarshal(&target->ecschnorr, buffer, size);
	break;
#endif
#if ALG_HMAC
      case TPM_ALG_HMAC:
	rc = TPMS_SCHEME_HMAC_Unmarshal(&target->hmac, buffer, size);
	break;
#endif
      case TPM_ALG_NULL:
	break;
      default:
	rc = TPM_RC_SELECTOR;
    }
    return rc;
}


TPMS_SCHEME_HASH_Unmarshal(TPMS_SCHEME_HASH *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    if (rc == TPM_RC_SUCCESS) {
	rc = TPMI_ALG_HASH_Unmarshal(&target->hashAlg, buffer, size, NO);
    }
    return rc;
}


TPM_SU_Unmarshal(TPM_SU *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPM_SU orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = UINT16_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	switch (*target) {
	  case TPM_SU_CLEAR:
	  case TPM_SU_STATE:
	    break;
	  default:
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPML_ALG_PROPERTY_Unmarshal(TPML_ALG_PROPERTY *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    UINT32 i;
   if (rc == TPM_RC_SUCCESS) {
	rc = UINT32_Unmarshal(&target->count, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	if (target->count > MAX_CAP_ALGS) {
	    rc = TPM_RC_SIZE;
	    target->count = 0; // libtpms added
	}
    }
    for (i = 0 ; (rc == TPM_RC_SUCCESS) && (i < target->count) ; i++) {
	rc = TPMS_ALG_PROPERTY_Unmarshal(&target->algProperties[i], buffer, size);
    }
    return rc;
}


TPMT_SYM_DEF_OBJECT_Unmarshal(TPMT_SYM_DEF_OBJECT *target, BYTE **buffer, INT32 *size, BOOL allowNull)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    if (rc == TPM_RC_SUCCESS) {
	rc = TPMI_ALG_SYM_OBJECT_Unmarshal(&target->algorithm, buffer, size, allowNull);
    }
    if (rc == TPM_RC_SUCCESS) {
	rc = TPMU_SYM_KEY_BITS_Unmarshal(&target->keyBits, buffer, size, target->algorithm);
    }
    if (rc == TPM_RC_SUCCESS) {
	rc = TPMU_SYM_MODE_Unmarshal(&target->mode, buffer, size, target->algorithm);
    }
    return rc;
}


TPMI_DH_PCR_Unmarshal(TPMI_DH_PCR *target, BYTE **buffer, INT32 *size, BOOL allowNull)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPMI_DH_PCR orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = TPM_HANDLE_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	BOOL isNotPcr = (*target > PCR_LAST);
	BOOL isNotLegalNull = (*target != TPM_RH_NULL) || !allowNull;
	if (isNotPcr &&
	    isNotLegalNull) {
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPM_CAP_Unmarshal(TPM_CAP *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;
    TPM_CAP orig_target = *target; // libtpms added

    if (rc == TPM_RC_SUCCESS) {
	rc = UINT32_Unmarshal(target, buffer, size);
    }
    if (rc == TPM_RC_SUCCESS) {
	switch (*target) {
	  case TPM_CAP_ALGS:
	  case TPM_CAP_HANDLES:
	  case TPM_CAP_COMMANDS:
	  case TPM_CAP_PP_COMMANDS:
	  case TPM_CAP_AUDIT_COMMANDS:
	  case TPM_CAP_PCRS:
	  case TPM_CAP_TPM_PROPERTIES:
	  case TPM_CAP_PCR_PROPERTIES:
	  case TPM_CAP_ECC_CURVES:
	  case TPM_CAP_AUTH_POLICIES:
	  case TPM_CAP_ACT:
	  case TPM_CAP_VENDOR_PROPERTY:
	    break;
	  default:
	    rc = TPM_RC_VALUE;
	    *target = orig_target; // libtpms added
	}
    }
    return rc;
}


TPMS_KEY_SCHEME_ECMQV_Unmarshal(TPMS_KEY_SCHEME_ECMQV *target, BYTE **buffer, INT32 *size)
{
    TPM_RC rc = TPM_RC_SUCCESS;

    if (rc == TPM_RC_SUCCESS) {
	rc = TPMS_SCHEME_HASH_Unmarshal(target, buffer, size);
    }
    return rc;
}


display_debug_pubnames (struct dwarf_section *section, void *file)
{
  return display_debug_pubnames_worker (section, file, 0);
}


size_of_encoded_value (int encoding)
{
  switch (encoding & 0x7)
    {
    default:	/* ??? */
    case 0:	return eh_addr_size;
    case 2:	return 2;
    case 3:	return 4;
    case 4:	return 8;
    }
}


regname_internal_by_table_only (unsigned int regno)
{
  if (dwarf_regnames != NULL
      && regno < dwarf_regnames_count
      && dwarf_regnames [regno] != NULL)
    return dwarf_regnames [regno];

  return NULL;
}


display_debug_aranges (struct dwarf_section *section,
		       void *file ATTRIBUTE_UNUSED)
{
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;

  introduce (section, false);

  /* It does not matter if this load fails,
     we test for that later on.  */
  load_debug_info (file);

  while (start < end)
    {
      unsigned char *hdrptr;
      DWARF2_Internal_ARange arange;
      unsigned char *addr_ranges;
      dwarf_vma length;
      dwarf_vma address;
      dwarf_vma     sec_off;
      unsigned char address_size;
      unsigned int  offset_size;
      unsigned char *end_ranges;

      hdrptr = start;
      sec_off = hdrptr - section->start;

      SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 4, end);
      if (arange.ar_length == 0xffffffff)
	{
	  SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 8, end);
	  offset_size = 8;
	}
      else
	offset_size = 4;

      if (arange.ar_length > (size_t) (end - hdrptr))
	{
	  warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
		section->name,
		(unsigned long) sec_off,
		dwarf_vmatoa ("x", arange.ar_length));
	  break;
	}
      end_ranges = hdrptr + arange.ar_length;

      SAFE_BYTE_GET_AND_INC (arange.ar_version, hdrptr, 2, end_ranges);
      SAFE_BYTE_GET_AND_INC (arange.ar_info_offset, hdrptr, offset_size,
			     end_ranges);

      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
	  && num_debug_info_entries > 0
	  && find_debug_info_for_offset (arange.ar_info_offset) == NULL)
	warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
	      (unsigned long) arange.ar_info_offset, section->name);

      SAFE_BYTE_GET_AND_INC (arange.ar_pointer_size, hdrptr, 1, end_ranges);
      SAFE_BYTE_GET_AND_INC (arange.ar_segment_size, hdrptr, 1, end_ranges);

      if (arange.ar_version != 2 && arange.ar_version != 3)
	{
	  /* PR 19872: A version number of 0 probably means that there is
	     padding at the end of the .debug_aranges section.  Gold puts
	     it there when performing an incremental link, for example.
	     So do not generate a warning in this case.  */
	  if (arange.ar_version)
	    warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
	  break;
	}

      printf (_("  Length:                   %ld\n"),
	      (long) arange.ar_length);
      printf (_("  Version:                  %d\n"), arange.ar_version);
      printf (_("  Offset into .debug_info:  0x%lx\n"),
	      (unsigned long) arange.ar_info_offset);
      printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
      printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);

      address_size = arange.ar_pointer_size + arange.ar_segment_size;

      /* PR 17512: file: 001-108546-0.001:0.1.  */
      if (address_size == 0 || address_size > 8)
	{
	  error (_("Invalid address size in %s section!\n"),
		 section->name);
	  break;
	}

      /* The DWARF spec does not require that the address size be a power
	 of two, but we do.  This will have to change if we ever encounter
	 an uneven architecture.  */
      if ((address_size & (address_size - 1)) != 0)
	{
	  warn (_("Pointer size + Segment size is not a power of two.\n"));
	  break;
	}

      if (address_size > 4)
	printf (_("\n    Address            Length\n"));
      else
	printf (_("\n    Address    Length\n"));

      addr_ranges = hdrptr;

      /* Must pad to an alignment boundary that is twice the address size.  */
      addr_ranges += (2 * address_size - 1
		      - (hdrptr - start - 1) % (2 * address_size));

      while (2 * address_size <= end_ranges - addr_ranges)
	{
	  SAFE_BYTE_GET_AND_INC (address, addr_ranges, address_size,
				 end_ranges);
	  SAFE_BYTE_GET_AND_INC (length, addr_ranges, address_size,
				 end_ranges);
	  printf ("    ");
	  print_dwarf_vma (address, address_size);
	  print_dwarf_vma (length, address_size);
	  putchar ('\n');
	}

      start = end_ranges;
    }

  printf ("\n");

  return 1;
}


add_dwo_id (const char * id, dwarf_vma cu_offset)
{
  add_dwo_info (id, cu_offset, DWO_ID);
}


add_dwo_name (const char * name, dwarf_vma cu_offset)
{
  add_dwo_info (name, cu_offset, DWO_NAME);
}


load_debug_sup_file (const char * main_filename, void * file)
{
  if (! load_debug_section (debug_sup, file))
    return; /* No .debug_sup section.  */

  struct dwarf_section * section;
  section = & debug_displays [debug_sup].section;
  assert (section != NULL);

  if (section->start == NULL || section->size < 5)
    {
      warn (_(".debug_sup section is corrupt/empty\n"));
      return;
    }

  if (section->start[2] != 0)
    return; /* This is a supplementary file.  */

  const char * filename = (const char *) section->start + 3;
  if (strnlen (filename, section->size - 3) == section->size - 3)
    {
      warn (_("filename in .debug_sup section is corrupt\n"));
      return;
    }

  if (filename[0] != '/' && strchr (main_filename, '/'))
    {
      char * new_name;
      int new_len;

      new_len = asprintf (& new_name, "%.*s/%s",
			  (int) (strrchr (main_filename, '/') - main_filename),
			  main_filename,
			  filename);
      if (new_len < 3)
	{
	  warn (_("unable to construct path for supplementary debug file"));
	  if (new_len > -1)
	    free (new_name);
	  return;
	}
      filename = new_name;
    }
  else
    {
      /* PR 27796: Make sure that we pass a filename that can be free'd to
	 add_separate_debug_file().  */
      filename = strdup (filename);
      if (filename == NULL)
	{
	  warn (_("out of memory constructing filename for .debug_sup link\n"));
	  return;
	}
    }

  void * handle = open_debug_file (filename);
  if (handle == NULL)
    {
      warn (_("unable to open file '%s' referenced from .debug_sup section\n"), filename);
      free ((void *) filename);
      return;
    }

  printf (_("%s: Found supplementary debug file: %s\n\n"), main_filename, filename);

  /* FIXME: Compare the checksums, if present.  */
  add_separate_debug_file (filename, handle);
}


display_loclists_list (struct dwarf_section *  section,
		       unsigned char **        start_ptr,
		       unsigned int            debug_info_entry,
		       dwarf_vma               offset,
		       dwarf_vma               base_address,
		       unsigned char **        vstart_ptr,
		       int                     has_frame_base)
{
  unsigned char *  start = *start_ptr;
  unsigned char *  vstart = *vstart_ptr;
  unsigned char *  section_end = section->start + section->size;
  dwarf_vma        cu_offset;
  unsigned int     pointer_size;
  unsigned int     offset_size;
  unsigned int     dwarf_version;

  /* Initialize it due to a false compiler warning.  */
  dwarf_vma begin = -1, vbegin = -1;
  dwarf_vma end = -1, vend = -1;
  dwarf_vma length;
  int need_frame_base;

  if (debug_info_entry >= num_debug_info_entries)
    {
      warn (_("No debug information available for "
	      "loclists lists of entry: %u\n"),
	    debug_info_entry);
      return;
    }

  cu_offset = debug_information [debug_info_entry].cu_offset;
  pointer_size = debug_information [debug_info_entry].pointer_size;
  offset_size = debug_information [debug_info_entry].offset_size;
  dwarf_version = debug_information [debug_info_entry].dwarf_version;

  if (pointer_size < 2 || pointer_size > 8)
    {
      warn (_("Invalid pointer size (%d) in debug info for entry %d\n"),
	    pointer_size, debug_info_entry);
      return;
    }

  while (1)
    {
      dwarf_vma off = offset + (start - *start_ptr);
      enum dwarf_location_list_entry_type llet;

      if (start + 1 > section_end)
	{
	  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		(unsigned long) offset);
	  break;
	}

      printf ("    ");
      print_dwarf_vma (off, 4);

      SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);

      if (vstart && (llet == DW_LLE_offset_pair
		     || llet == DW_LLE_start_end
		     || llet == DW_LLE_start_length))
	{
	  off = offset + (vstart - *start_ptr);

	  READ_ULEB (vbegin, vstart, section_end);
	  print_dwarf_view (vbegin, pointer_size, 1);

	  READ_ULEB (vend, vstart, section_end);
	  print_dwarf_view (vend, pointer_size, 1);

	  printf (_("views at %8.8lx for:\n    %*s "),
		  (unsigned long) off, 8, "");
	}

      switch (llet)
	{
	case DW_LLE_end_of_list:
	  printf (_("<End of list>\n"));
	  break;

	case DW_LLE_base_addressx:
	  READ_ULEB (base_address, start, section_end);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(index into .debug_addr) "));
	  base_address = fetch_indexed_addr (base_address, pointer_size);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(base address)\n"));
	  break;

	case DW_LLE_startx_endx:
	  READ_ULEB (begin, start, section_end);
	  begin = fetch_indexed_addr (begin, pointer_size);
	  READ_ULEB (end, start, section_end);
	  end = fetch_indexed_addr (end, pointer_size);
	  break;

	case DW_LLE_startx_length:
	  READ_ULEB (begin, start, section_end);
	  begin = fetch_indexed_addr (begin, pointer_size);
	  READ_ULEB (end, start, section_end);
	  end += begin;
	  break;

	case DW_LLE_default_location:
	  begin = end = 0;
	  break;

	case DW_LLE_offset_pair:
	  READ_ULEB (begin, start, section_end);
	  begin += base_address;
	  READ_ULEB (end, start, section_end);
	  end += base_address;
	  break;

	case DW_LLE_base_address:
	  SAFE_BYTE_GET_AND_INC (base_address, start, pointer_size,
				 section_end);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(base address)\n"));
	  break;

	case DW_LLE_start_end:
	  SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
	  SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
	  break;

	case DW_LLE_start_length:
	  SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
	  READ_ULEB (end, start, section_end);
	  end += begin;
	  break;

#ifdef DW_LLE_view_pair
	case DW_LLE_view_pair:
	  if (vstart)
	    printf (_("View pair entry in loclist with locviews attribute\n"));
	  READ_ULEB (vbegin, start, section_end);
	  print_dwarf_view (vbegin, pointer_size, 1);

	  READ_ULEB (vend, start, section_end);
	  print_dwarf_view (vend, pointer_size, 1);

	  printf (_("views for:\n"));
	  continue;
#endif

	default:
	  error (_("Invalid location list entry type %d\n"), llet);
	  return;
	}

      if (llet == DW_LLE_end_of_list)
	break;

      if (llet == DW_LLE_base_address
	  || llet == DW_LLE_base_addressx)
	continue;

      if (start == section_end)
	{
	  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		(unsigned long) offset);
	  break;
	}
      READ_ULEB (length, start, section_end);

      if (length > (size_t) (section_end - start))
	{
	  warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		(unsigned long) offset);
	  break;
	}

      print_dwarf_vma (begin, pointer_size);
      print_dwarf_vma (end, pointer_size);

      putchar ('(');
      need_frame_base = decode_location_expression (start,
						    pointer_size,
						    offset_size,
						    dwarf_version,
						    length,
						    cu_offset, section);
      putchar (')');

      if (need_frame_base && !has_frame_base)
	printf (_(" [without DW_AT_frame_base]"));

      if (begin == end && vbegin == vend)
	fputs (_(" (start == end)"), stdout);
      else if (begin > end || (begin == end && vbegin > vend))
	fputs (_(" (start > end)"), stdout);

      putchar ('\n');

      start += length;
      vbegin = vend = -1;
    }

  if (vbegin != vm1 || vend != vm1)
    printf (_("Trailing view pair not used in a range"));

  *start_ptr = start;
  *vstart_ptr = vstart;
}


free_debug_memory (void)
{
  unsigned int i;

  free_all_abbrevs ();

  free (shndx_pool);
  shndx_pool = NULL;
  shndx_pool_size = 0;
  shndx_pool_used = 0;
  free (cu_sets);
  cu_sets = NULL;
  cu_count = 0;
  free (tu_sets);
  tu_sets = NULL;
  tu_count = 0;

  memset (level_type_signed, 0, sizeof level_type_signed);
  cu_tu_indexes_read = -1;

  for (i = 0; i < max; i++)
    free_debug_section ((enum dwarf_section_display_enum) i);

  if (debug_information != NULL)
    {
      for (i = 0; i < alloc_num_debug_info_entries; i++)
	{
	  if (debug_information [i].max_loc_offsets)
	    {
	      free (debug_information [i].loc_offsets);
	      free (debug_information [i].have_frame_base);
	    }
	  if (debug_information [i].max_range_lists)
	    free (debug_information [i].range_lists);
	}
      free (debug_information);
      debug_information = NULL;
      alloc_num_debug_info_entries = num_debug_info_entries = 0;
    }

  separate_info * d;
  separate_info * next;

  for (d = first_separate_info; d != NULL; d = next)
    {
      close_debug_file (d->handle);
      free ((void *) d->filename);
      next = d->next;
      free ((void *) d);
    }
  first_separate_info = NULL;

  free_dwo_info ();
}


display_cu_index (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
{
  return process_cu_tu_index (section, 1);
}


display_offset_entry_loclists (struct dwarf_section *section)
{
  unsigned char *  start = section->start;
  unsigned char * const end = start + section->size;

  introduce (section, false);

  do
    {
      dwarf_vma        length;
      unsigned short   version;
      unsigned char    address_size;
      unsigned char    segment_selector_size;
      uint32_t         offset_entry_count;
      uint32_t         i;
      bool             is_64bit;

      printf (_("Table at Offset 0x%lx\n"), (long)(start - section->start));

      SAFE_BYTE_GET_AND_INC (length, start, 4, end);
      if (length == 0xffffffff)
	{
	  is_64bit = true;
	  SAFE_BYTE_GET_AND_INC (length, start, 8, end);
	}
      else
	is_64bit = false;

      SAFE_BYTE_GET_AND_INC (version, start, 2, end);
      SAFE_BYTE_GET_AND_INC (address_size, start, 1, end);
      SAFE_BYTE_GET_AND_INC (segment_selector_size, start, 1, end);
      SAFE_BYTE_GET_AND_INC (offset_entry_count, start, 4, end);

      printf (_("  Length:          0x%s\n"), dwarf_vmatoa ("x", length));
      printf (_("  DWARF version:   %u\n"), version);
      printf (_("  Address size:    %u\n"), address_size);
      printf (_("  Segment size:    %u\n"), segment_selector_size);
      printf (_("  Offset entries:  %u\n"), offset_entry_count);

      if (version < 5)
	{
	  warn (_("The %s section contains a corrupt or "
		  "unsupported version number: %d.\n"),
		section->name, version);
	  return 0;
	}

      if (segment_selector_size != 0)
	{
	  warn (_("The %s section contains an "
		  "unsupported segment selector size: %d.\n"),
		section->name, segment_selector_size);
	  return 0;
	}

      if (offset_entry_count == 0)
	{
	  warn (_("The %s section contains a table without offset\n"),
		section->name);
	  return 0;
	}

      printf (_("\n   Offset Entries starting at 0x%lx:\n"),
	      (long)(start - section->start));

      if (is_64bit)
	{
	  for (i = 0; i < offset_entry_count; i++)
	    {
	      dwarf_vma entry;

	      SAFE_BYTE_GET_AND_INC (entry, start, 8, end);
	      printf (_("    [%6u] 0x%s\n"), i, dwarf_vmatoa ("x", entry));
	    }
	}
      else
	{
	  for (i = 0; i < offset_entry_count; i++)
	    {
	      uint32_t entry;

	      SAFE_BYTE_GET_AND_INC (entry, start, 4, end);
	      printf (_("    [%6u] 0x%x\n"), i, entry);
	    }
	}

      putchar ('\n');

      uint32_t j;

      for (j = 1, i = 0; i < offset_entry_count;)
	{
	  unsigned char  lle;
	  dwarf_vma      base_address = 0;
	  dwarf_vma      begin;
	  dwarf_vma      finish;
	  dwarf_vma      off = start - section->start;

	  if (j != i)
	    {
	      printf (_("   Offset Entry %u\n"), i);
	      j = i;
	    }

	  printf ("    ");
	  print_dwarf_vma (off, 4);

	  SAFE_BYTE_GET_AND_INC (lle, start, 1, end);

	  switch (lle)
	    {
	    case DW_LLE_end_of_list:
	      printf (_("<End of list>\n\n"));
	      i ++;
	      continue;

	    case DW_LLE_base_addressx:
	      READ_ULEB (base_address, start, end);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(index into .debug_addr) "));
	      base_address = fetch_indexed_addr (base_address, address_size);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(base address)\n"));
	      continue;

	    case DW_LLE_startx_endx:
	      READ_ULEB (begin, start, end);
	      begin = fetch_indexed_addr (begin, address_size);
	      READ_ULEB (finish, start, end);
	      finish = fetch_indexed_addr (finish, address_size);
	      break;

	    case DW_LLE_startx_length:
	      READ_ULEB (begin, start, end);
	      begin = fetch_indexed_addr (begin, address_size);
	      READ_ULEB (finish, start, end);
	      finish += begin;
	      break;

	    case DW_LLE_offset_pair:
	      READ_ULEB (begin, start, end);
	      begin += base_address;
	      READ_ULEB (finish, start, end);
	      finish += base_address;
	      break;

	    case DW_LLE_default_location:
	      begin = finish = 0;
	      break;

	    case DW_LLE_base_address:
	      SAFE_BYTE_GET_AND_INC (base_address, start, address_size, end);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(base address)\n"));
	      continue;

	    case DW_LLE_start_end:
	      SAFE_BYTE_GET_AND_INC (begin,  start, address_size, end);
	      SAFE_BYTE_GET_AND_INC (finish, start, address_size, end);
	      break;

	    case DW_LLE_start_length:
	      SAFE_BYTE_GET_AND_INC (begin, start, address_size, end);
	      READ_ULEB (finish, start, end);
	      finish += begin;
	      break;

	    default:
	      error (_("Invalid location list entry type %d\n"), lle);
	      return 0;
	    }

	  if (start == end)
	    {
	      warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		    (unsigned long) off);
	      break;
	    }

	  print_dwarf_vma (begin, address_size);
	  print_dwarf_vma (finish, address_size);

	  if (begin == finish)
	    fputs (_(" (start == end)"), stdout);
	  else if (begin > finish)
	    fputs (_(" (start > end)"), stdout);

	  /* Read the counted location descriptions.  */
	  READ_ULEB (length, start, end);

	  if (length > (size_t) (end - start))
	    {
	      warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		    (unsigned long) off);
	      break;
	    }

	  putchar (' ');
	  (void) decode_location_expression (start, address_size, address_size,
					     version, length, 0, section);
	  start += length;
	  putchar ('\n');
	}

      putchar ('\n');
    }
  while (start < end);

  return 1;
}


check_gnu_debugaltlink (const char * filename, void * data ATTRIBUTE_UNUSED)
{
  void * sep_data = open_debug_file (filename);

  if (sep_data == NULL)
    return false;

  /* FIXME: We should now extract the build-id in the separate file
     and check it...  */

  return true;
}


display_trace_info (struct dwarf_section *section, void *file)
{
  return process_debug_info (section, file, section->abbrev_sec, false, true);
}


read_and_display_attr (unsigned long           attribute,
		       unsigned long           form,
		       dwarf_signed_vma        implicit_const,
		       unsigned char *         start,
		       unsigned char *         data,
		       unsigned char *         end,
		       dwarf_vma               cu_offset,
		       dwarf_vma               pointer_size,
		       dwarf_vma               offset_size,
		       int                     dwarf_version,
		       debug_info *            debug_info_p,
		       int                     do_loc,
		       struct dwarf_section *  section,
		       struct cu_tu_set *      this_set,
		       int                     level)
{
  if (!do_loc)
    printf ("   %-18s:", get_AT_name (attribute));
  data = read_and_display_attr_value (attribute, form, implicit_const,
				      start, data, end,
				      cu_offset, pointer_size, offset_size,
				      dwarf_version, debug_info_p,
				      do_loc, section, this_set, ' ', level);
  if (!do_loc)
    printf ("\n");
  return data;
}


prealloc_cu_tu_list (unsigned int nshndx)
{
  if (shndx_pool == NULL)
    {
      shndx_pool_size = nshndx;
      shndx_pool_used = 0;
      shndx_pool = (unsigned int *) xcmalloc (shndx_pool_size,
					      sizeof (unsigned int));
    }
  else
    {
      shndx_pool_size = shndx_pool_used + nshndx;
      shndx_pool = (unsigned int *) xcrealloc (shndx_pool, shndx_pool_size,
					       sizeof (unsigned int));
    }
}


read_and_print_leb128 (unsigned char *data,
		       unsigned int *bytes_read,
		       unsigned const char *end,
		       bool is_signed)
{
  int status;
  dwarf_vma val = read_leb128 (data, end, is_signed, bytes_read, &status);
  if (status != 0)
    report_leb_status (status);
  else
    printf ("%s", dwarf_vmatoa (is_signed ? "d" : "u", val));
}


get_gdb_index_symbol_kind_name (gdb_index_symbol_kind kind)
{
  /* See gdb/gdb-index.h.  */
  static const char * const kinds[] =
  {
    N_ ("no info"),
    N_ ("type"),
    N_ ("variable"),
    N_ ("function"),
    N_ ("other"),
    N_ ("unused5"),
    N_ ("unused6"),
    N_ ("unused7")
  };

  return _ (kinds[kind]);
}


display_debug_ranges (struct dwarf_section *section,
		      void *file ATTRIBUTE_UNUSED)
{
  unsigned char *       start = section->start;
  unsigned char *       last_start = start;
  dwarf_vma             bytes = section->size;
  unsigned char *       section_begin = start;
  unsigned char *       finish = start + bytes;
  unsigned int          num_range_list, i;
  struct range_entry *  range_entries;
  struct range_entry *  range_entry_fill;
  int                   is_rnglists = strstr (section->name, "debug_rnglists") != NULL;
  /* Initialize it due to a false compiler warning.  */
  unsigned char         address_size = 0;
  dwarf_vma             last_offset = 0;

  if (bytes == 0)
    {
      printf (_("\nThe %s section is empty.\n"), section->name);
      return 0;
    }

  introduce (section, false);

  if (is_rnglists)
    return display_debug_rnglists (section);

  if (load_debug_info (file) == 0)
    {
      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
	    section->name);
      return 0;
    }

  num_range_list = 0;
  for (i = 0; i < num_debug_info_entries; i++)
    num_range_list += debug_information [i].num_range_lists;

  if (num_range_list == 0)
    {
      /* This can happen when the file was compiled with -gsplit-debug
	 which removes references to range lists from the primary .o file.  */
      printf (_("No range lists in .debug_info section.\n"));
      return 1;
    }

  range_entries = (struct range_entry *)
      xmalloc (sizeof (*range_entries) * num_range_list);
  range_entry_fill = range_entries;

  for (i = 0; i < num_debug_info_entries; i++)
    {
      debug_info *debug_info_p = &debug_information[i];
      unsigned int j;

      for (j = 0; j < debug_info_p->num_range_lists; j++)
	{
	  range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
	  range_entry_fill->debug_info_p = debug_info_p;
	  range_entry_fill++;
	}
    }

  qsort (range_entries, num_range_list, sizeof (*range_entries),
	 range_entry_compar);

  if (dwarf_check != 0 && range_entries[0].ranges_offset != 0)
    warn (_("Range lists in %s section start at 0x%lx\n"),
	  section->name, (unsigned long) range_entries[0].ranges_offset);

  putchar ('\n');
  printf (_("    Offset   Begin    End\n"));

  for (i = 0; i < num_range_list; i++)
    {
      struct range_entry *range_entry = &range_entries[i];
      debug_info *debug_info_p = range_entry->debug_info_p;
      unsigned int pointer_size;
      dwarf_vma offset;
      unsigned char *next;
      dwarf_vma base_address;

      pointer_size = (is_rnglists ? address_size : debug_info_p->pointer_size);
      offset = range_entry->ranges_offset;
      base_address = debug_info_p->base_address;

      /* PR 17512: file: 001-101485-0.001:0.1.  */
      if (pointer_size < 2 || pointer_size > 8)
	{
	  warn (_("Corrupt pointer size (%d) in debug entry at offset %8.8lx\n"),
		pointer_size, (unsigned long) offset);
	  continue;
	}

      if (offset > (size_t) (finish - section_begin))
	{
	  warn (_("Corrupt offset (%#8.8lx) in range entry %u\n"),
		(unsigned long) offset, i);
	  continue;
	}

      next = section_begin + offset + debug_info_p->rnglists_base;

      /* If multiple DWARF entities reference the same range then we will
	 have multiple entries in the `range_entries' list for the same
	 offset.  Thanks to the sort above these will all be consecutive in
	 the `range_entries' list, so we can easily ignore duplicates
	 here.  */
      if (i > 0 && last_offset == offset)
	continue;
      last_offset = offset;

      if (dwarf_check != 0 && i > 0)
	{
	  if (start < next)
	    warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
		  (unsigned long) (start - section_begin),
		  (unsigned long) (next - section_begin), section->name);
	  else if (start > next)
	    {
	      if (next == last_start)
		continue;
	      warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
		    (unsigned long) (start - section_begin),
		    (unsigned long) (next - section_begin), section->name);
	    }
	}

      start = next;
      last_start = next;

      display_debug_ranges_list
	(start, finish, pointer_size, offset, base_address);
    }
  putchar ('\n');

  free (range_entries);

  return 1;
}


display_formatted_table (unsigned char *data,
			 unsigned char *start,
			 unsigned char *end,
			 const DWARF2_Internal_LineInfo *linfo,
			 struct dwarf_section *section,
			 bool is_dir)
{
  unsigned char *format_start, format_count, *format, formati;
  dwarf_vma data_count, datai;
  unsigned int namepass, last_entry = 0;
  const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");

  SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
  if (do_checks && format_count > 5)
    warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
	  table_name, format_count);

  format_start = data;
  for (formati = 0; formati < format_count; formati++)
    {
      SKIP_ULEB (data, end);
      SKIP_ULEB (data, end);
      if (data >= end)
	{
	  warn (_("%s: Corrupt format description entry\n"), table_name);
	  return data;
	}
    }

  READ_ULEB (data_count, data, end);
  if (data_count == 0)
    {
      printf (_("\n The %s is empty.\n"), table_name);
      return data;
    }
  else if (data >= end)
    {
      warn (_("%s: Corrupt entry count - expected %s but none found\n"),
	    table_name, dwarf_vmatoa ("x", data_count));
      return data;
    }

  else if (format_count == 0)
    {
      warn (_("%s: format count is zero, but the table is not empty\n"),
	    table_name);
      return end;
    }

  printf (_("\n The %s (offset 0x%lx, lines %s, columns %u):\n"),
	  table_name, (long) (data - start), dwarf_vmatoa ("u", data_count),
	  format_count);

  printf (_("  Entry"));
  /* Delay displaying name as the last entry for better screen layout.  */
  for (namepass = 0; namepass < 2; namepass++)
    {
      format = format_start;
      for (formati = 0; formati < format_count; formati++)
	{
	  dwarf_vma content_type;

	  READ_ULEB (content_type, format, end);
	  if ((content_type == DW_LNCT_path) == (namepass == 1))
	    switch (content_type)
	      {
	      case DW_LNCT_path:
		printf (_("\tName"));
		break;
	      case DW_LNCT_directory_index:
		printf (_("\tDir"));
		break;
	      case DW_LNCT_timestamp:
		printf (_("\tTime"));
		break;
	      case DW_LNCT_size:
		printf (_("\tSize"));
		break;
	      case DW_LNCT_MD5:
		printf (_("\tMD5\t\t\t"));
		break;
	      default:
		printf (_("\t(Unknown format content type %s)"),
			dwarf_vmatoa ("u", content_type));
	      }
	  SKIP_ULEB (format, end);
	}
    }
  putchar ('\n');

  for (datai = 0; datai < data_count; datai++)
    {
      unsigned char *datapass = data;

      printf ("  %d", last_entry++);
      /* Delay displaying name as the last entry for better screen layout.  */
      for (namepass = 0; namepass < 2; namepass++)
	{
	  format = format_start;
	  data = datapass;
	  for (formati = 0; formati < format_count; formati++)
	    {
	      dwarf_vma content_type, form;

	      READ_ULEB (content_type, format, end);
	      READ_ULEB (form, format, end);
	      data = read_and_display_attr_value (0, form, 0, start, data, end,
						  0, 0, linfo->li_offset_size,
						  linfo->li_version, NULL,
			    ((content_type == DW_LNCT_path) != (namepass == 1)),
						  section, NULL, '\t', -1);
	    }
	}

      if (data >= end && (datai < data_count - 1))
	{
	  warn (_("\n%s: Corrupt entries list\n"), table_name);
	  return data;
	}
      putchar ('\n');
    }
  return data;
}


parse_gnu_debuglink (struct dwarf_section * section, void * data)
{
  const char *     name;
  unsigned int     crc_offset;
  unsigned long *  crc32 = (unsigned long *) data;

  /* The name is first.
     The CRC value is stored after the filename, aligned up to 4 bytes.  */
  name = (const char *) section->start;

  crc_offset = strnlen (name, section->size) + 1;
  if (crc_offset == 1)
    return NULL;
  crc_offset = (crc_offset + 3) & ~3;
  if (crc_offset + 4 > section->size)
    return NULL;

  * crc32 = byte_get (section->start + crc_offset, 4);
  return name;
}


parser_check_assignment_expr (parser_context_t *context_p)
{
  if (!parser_is_assignment_expr (context_p))
  {
    parser_raise_error (context_p, PARSER_ERR_ASSIGNMENT_EXPECTED);
  }
} /* parser_check_assignment_expr */


parser_save_context (parser_context_t *context_p, /**< context */
                     parser_saved_context_t *saved_context_p) /**< target for saving the context */
{
  JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);

#if JERRY_DEBUGGER
  if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
      && context_p->breakpoint_info_count > 0)
  {
    parser_send_breakpoints (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST);
    context_p->breakpoint_info_count = 0;
  }
#endif /* JERRY_DEBUGGER */

#if JERRY_ESNEXT
  if (context_p->status_flags & PARSER_FUNCTION_IS_PARSING_ARGS)
  {
    context_p->status_flags |= PARSER_LEXICAL_BLOCK_NEEDED;
  }
#endif /* JERRY_ESNEXT */

  /* Save private part of the context. */

  saved_context_p->status_flags = context_p->status_flags;
  saved_context_p->stack_depth = context_p->stack_depth;
  saved_context_p->stack_limit = context_p->stack_limit;
  saved_context_p->prev_context_p = context_p->last_context_p;
  saved_context_p->last_statement = context_p->last_statement;

  saved_context_p->argument_count = context_p->argument_count;
#if JERRY_ESNEXT
  saved_context_p->argument_length = context_p->argument_length;
#endif /* JERRY_ESNEXT */
  saved_context_p->register_count = context_p->register_count;
  saved_context_p->literal_count = context_p->literal_count;

  saved_context_p->byte_code = context_p->byte_code;
  saved_context_p->byte_code_size = context_p->byte_code_size;
  saved_context_p->literal_pool_data = context_p->literal_pool.data;
  saved_context_p->scope_stack_p = context_p->scope_stack_p;
  saved_context_p->scope_stack_size = context_p->scope_stack_size;
  saved_context_p->scope_stack_top = context_p->scope_stack_top;
  saved_context_p->scope_stack_reg_top = context_p->scope_stack_reg_top;
#if JERRY_ESNEXT
  saved_context_p->scope_stack_global_end = context_p->scope_stack_global_end;
  saved_context_p->tagged_template_literal_cp = context_p->tagged_template_literal_cp;
#endif /* JERRY_ESNEXT */

#ifndef JERRY_NDEBUG
  saved_context_p->context_stack_depth = context_p->context_stack_depth;
#endif /* !JERRY_NDEBUG */

#if JERRY_LINE_INFO
  saved_context_p->line_info_p = context_p->line_info_p;
#endif /* JERRY_LINE_INFO */

  /* Reset private part of the context. */

  context_p->status_flags &= PARSER_IS_STRICT;
  context_p->stack_depth = 0;
  context_p->stack_limit = 0;
  context_p->last_context_p = saved_context_p;
  context_p->last_statement.current_p = NULL;

  context_p->argument_count = 0;
#if JERRY_ESNEXT
  context_p->argument_length = UINT16_MAX;
#endif /* JERRY_ESNEXT */
  context_p->register_count = 0;
  context_p->literal_count = 0;

  parser_cbc_stream_init (&context_p->byte_code);
  context_p->byte_code_size = 0;
  parser_list_reset (&context_p->literal_pool);
  context_p->scope_stack_p = NULL;
  context_p->scope_stack_size = 0;
  context_p->scope_stack_top = 0;
  context_p->scope_stack_reg_top = 0;
#if JERRY_ESNEXT
  context_p->scope_stack_global_end = 0;
  context_p->tagged_template_literal_cp = JMEM_CP_NULL;
#endif /* JERRY_ESNEXT */

#ifndef JERRY_NDEBUG
  context_p->context_stack_depth = 0;
#endif /* !JERRY_NDEBUG */

#if JERRY_LINE_INFO
  context_p->line_info_p = NULL;
#endif /* JERRY_LINE_INFO */
} /* parser_save_context */


parser_append_binary_token (parser_context_t *context_p) /**< context */
{
  JERRY_ASSERT (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type));
  parser_push_result (context_p);

  if (context_p->token.type == LEXER_ASSIGN)
  {
    parser_append_binary_single_assignment_token (context_p, 0);
    return;
  }

  if (LEXER_IS_BINARY_LVALUE_OP_TOKEN (context_p->token.type))
  {
    if (PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode)
        && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
    {
      parser_check_invalid_assign (context_p);

      parser_emit_ident_reference (context_p, CBC_PUSH_IDENT_REFERENCE);

#if JERRY_ESNEXT
      if (scanner_literal_is_const_reg (context_p, context_p->last_cbc.literal_index))
      {
        parser_stack_push_uint8 (context_p, LEXER_ASSIGN_CONST);
      }
#endif /* JERRY_ESNEXT */
    }
    else if (PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode))
    {
      context_p->last_cbc_opcode = PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE (context_p->last_cbc_opcode);
    }
    else
    {
      /* Invalid LeftHandSide expression. */
#if JERRY_ESNEXT
      parser_check_invalid_new_target (context_p, CBC_ASSIGN);
      parser_raise_error (context_p, PARSER_ERR_INVALID_LHS_ASSIGNMENT);
#else /* !JERRY_ESNEXT */
      parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
#endif /* JERRY_ESNEXT */

      parser_emit_cbc (context_p, CBC_PUSH_PROP_REFERENCE);
    }
  }
  else if (context_p->token.type == LEXER_LOGICAL_OR
           || context_p->token.type == LEXER_LOGICAL_AND)
  {
    parser_branch_t branch;
    uint16_t opcode = CBC_BRANCH_IF_LOGICAL_TRUE;

    if (context_p->token.type == LEXER_LOGICAL_AND)
    {
      opcode = CBC_BRANCH_IF_LOGICAL_FALSE;
    }

#if JERRY_ESNEXT
    parser_check_invalid_logical_op (context_p, LEXER_NULLISH_COALESCING, LEXER_NULLISH_COALESCING);
#endif /* JERRY_ESNEXT */

    parser_emit_cbc_forward_branch (context_p, opcode, &branch);
    parser_stack_push (context_p, &branch, sizeof (parser_branch_t));
    parser_stack_push_uint8 (context_p, context_p->token.type);
    return;
  }
#if JERRY_ESNEXT
  else if (context_p->token.type == LEXER_NULLISH_COALESCING)
  {
    parser_branch_t branch;

    uint16_t opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_BRANCH_IF_NULLISH);
    parser_emit_cbc_forward_branch (context_p, opcode, &branch);
    parser_stack_push (context_p, &branch, sizeof (parser_branch_t));
    parser_stack_push_uint8 (context_p, context_p->token.type);
    return;
  }
#endif /* JERRY_ESNEXT */

  parser_stack_push_uint8 (context_p, context_p->token.type);
} /* parser_append_binary_token */


scanner_detect_invalid_var (parser_context_t *context_p, /**< context */
                            scanner_context_t *scanner_context_p, /**< scanner context */
                            lexer_lit_location_t *var_literal_p) /**< var literal */
{
  if (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL
      && !(var_literal_p->type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_ARG))
      && (var_literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL)
  {
    scanner_raise_redeclaration_error (context_p);
  }

  scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;

  if (!(literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION)
      && ((var_literal_p->type & SCANNER_LITERAL_IS_LOCAL_FUNC) == SCANNER_LITERAL_IS_LOCAL_FUNC))
  {
    scanner_raise_redeclaration_error (context_p);
  }

  const uint8_t *char_p = var_literal_p->char_p;
  prop_length_t length = var_literal_p->length;

  while (!(literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION))
  {
    literal_pool_p = literal_pool_p->prev_p;

    parser_list_iterator_t literal_iterator;
    parser_list_iterator_init (&literal_pool_p->literal_pool, &literal_iterator);
    lexer_lit_location_t *literal_p;

    if (JERRY_LIKELY (!(context_p->token.lit_location.status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE)))
    {
      while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
      {
        if ((literal_p->type & SCANNER_LITERAL_IS_LOCAL)
            && !(literal_p->type & SCANNER_LITERAL_IS_ARG)
            && !((literal_p->type & SCANNER_LITERAL_IS_FUNC)
                 && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION))
            && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL
            && literal_p->length == length)
        {
          if (JERRY_LIKELY (!(literal_p->status_flags & LEXER_LIT_LOCATION_HAS_ESCAPE)))
          {
            if (memcmp (literal_p->char_p, char_p, length) == 0)
            {
              scanner_raise_redeclaration_error (context_p);
              return;
            }
          }
          else if (lexer_compare_identifier_to_string (literal_p, char_p, length))
          {
            scanner_raise_redeclaration_error (context_p);
            return;
          }
        }
      }
    }
    else
    {
      while ((literal_p = (lexer_lit_location_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
      {
        if ((literal_p->type & SCANNER_LITERAL_IS_LOCAL)
            && !(literal_p->type & SCANNER_LITERAL_IS_ARG)
            && !((literal_p->type & SCANNER_LITERAL_IS_FUNC)
                 && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION))
            && (literal_p->type & SCANNER_LITERAL_IS_LOCAL) != SCANNER_LITERAL_IS_LOCAL
            && lexer_compare_identifiers (context_p, literal_p, var_literal_p))
        {
          scanner_raise_redeclaration_error (context_p);
          return;
        }
      }
    }
  }

  if (scanner_scope_find_lexical_declaration (context_p, var_literal_p))
  {
    scanner_raise_redeclaration_error (context_p);
  }
} /* scanner_detect_invalid_var */


parser_pop_block_context (parser_context_t *context_p) /**< context */
{
  JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_SCOPE
                || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE
                || context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT
                || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT);

  uint8_t type = context_p->stack_top_uint8;

  parser_block_statement_t block_statement;

  parser_stack_pop_uint8 (context_p);
  parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));

  context_p->scope_stack_top = block_statement.scope_stack_top;
  context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;

  if (type == PARSER_STATEMENT_BLOCK_CONTEXT || type == PARSER_STATEMENT_PRIVATE_CONTEXT)
  {
    PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
    PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

    parser_block_context_t block_context;
    parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t));

    parser_emit_cbc (context_p, CBC_CONTEXT_END);
    parser_set_branch_to_current_position (context_p, &block_context.branch);
  }

  parser_stack_iterator_init (context_p, &context_p->last_statement);
} /* parser_pop_block_context */


parser_parse_expression_statement (parser_context_t *context_p, /**< context */
                                   int options) /**< option flags */
{
  parser_parse_expression (context_p, options | PARSE_EXPR_NO_PUSH_RESULT);

  if (!CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode))
  {
    parser_emit_cbc (context_p, CBC_POP);
  }
} /* parser_parse_expression_statement */


parser_module_append_export_name (parser_context_t *context_p) /**< parser context */
{
  if (!(context_p->status_flags & PARSER_MODULE_STORE_IDENT))
  {
    return;
  }

  context_p->module_identifier_lit_p = context_p->lit_object.literal_p;
  ecma_string_t *name_p  = parser_new_ecma_string_from_literal (context_p->lit_object.literal_p);

  if (parser_module_check_duplicate_export (context_p, name_p))
  {
    ecma_deref_ecma_string (name_p);
    parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER);
  }

  parser_module_add_names_to_node (context_p,
                                   name_p,
                                   name_p);
  ecma_deref_ecma_string (name_p);
} /* parser_module_append_export_name */


ecma_bigint_to_bigint (ecma_value_t value, /**< any value */
                       bool allow_numbers) /**< converting ecma numbers is allowed */
{
  bool free_value = false;

  if (ecma_is_value_object (value))
  {
    value = ecma_op_object_default_value (ecma_get_object_from_value (value), ECMA_PREFERRED_TYPE_NUMBER);
    free_value = true;

    if (ECMA_IS_VALUE_ERROR (value))
    {
      return value;
    }
  }

  ecma_value_t result;

  if (ecma_is_value_string (value))
  {
    result = ecma_bigint_parse_string_value (value, ECMA_BIGINT_PARSE_NO_OPTIONS);
  }
  else if (ecma_is_value_bigint (value))
  {
    result = value;

    if (!free_value && value != ECMA_BIGINT_ZERO)
    {
      ecma_ref_extended_primitive (ecma_get_extended_primitive_from_value (value));
    }
    else
    {
      free_value = false;
    }
  }
  else if (allow_numbers && ecma_is_value_number (value))
  {
    result = ecma_bigint_number_to_bigint (ecma_get_number_from_value (value));
  }
  else if (ecma_is_value_false (value))
  {
    result = ECMA_BIGINT_ZERO;
  }
  else if (ecma_is_value_true (value))
  {
    result = ecma_bigint_create_from_digit (1, false);
  }
  else
  {
    result = ecma_raise_type_error (ECMA_ERR_MSG ("Value cannot be converted to BigInt"));
  }

  if (free_value)
  {
    ecma_free_value (value);
  }

  return result;
} /* ecma_bigint_to_bigint */


ecma_bigint_shift (ecma_value_t left_value, /**< left BigInt value */
                   ecma_value_t right_value, /**< right BigInt value */
                   bool is_left) /**< true if left shift operation should be performed */
{
  JERRY_ASSERT (ecma_is_value_bigint (left_value) && ecma_is_value_bigint (right_value));

  if (left_value == ECMA_BIGINT_ZERO)
  {
    return ECMA_BIGINT_ZERO;
  }

  ecma_extended_primitive_t *left_p = ecma_get_extended_primitive_from_value (left_value);

  if (right_value == ECMA_BIGINT_ZERO)
  {
    ecma_ref_extended_primitive (left_p);
    return left_value;
  }

  ecma_extended_primitive_t *right_p = ecma_get_extended_primitive_from_value (right_value);

  if (right_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
  {
    is_left = !is_left;
  }

  if (ECMA_BIGINT_GET_SIZE (right_p) > sizeof (ecma_bigint_digit_t))
  {
    if (is_left)
    {
      return ecma_bigint_raise_memory_error ();
    }
    else if (left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN)
    {
      /* Shifting a negative value with a very big number to the right should be -1. */
      return ecma_bigint_create_from_digit (1, true);
    }

    return ECMA_BIGINT_ZERO;
  }

  ecma_extended_primitive_t *result_p;
  ecma_bigint_digit_t shift = ECMA_BIGINT_GET_LAST_DIGIT (right_p, sizeof (ecma_bigint_digit_t));
  uint32_t left_sign = left_p->u.bigint_sign_and_size & ECMA_BIGINT_SIGN;

  if (is_left)
  {
    result_p = ecma_big_uint_shift_left (left_p, shift);
  }
  else
  {
    /* -x >> y == ~(x - 1) >> y == ~((x - 1) >> y) == -(((x - 1) >> y) + 1)
     * When a non-zero bit is shifted out: (x - 1) >> y == x >> y, so the formula is -((x >> y) + 1)
     * When only zero bits are shifted out: (((x - 1) >> y) + 1) == x >> y so the formula is: -(x >> y) */
    result_p = ecma_big_uint_shift_right (left_p, shift, left_sign != 0);

    if (result_p == ECMA_BIGINT_POINTER_TO_ZERO)
    {
      return ECMA_BIGINT_ZERO;
    }
  }

  if (JERRY_UNLIKELY (result_p == NULL))
  {
    return ecma_bigint_raise_memory_error ();
  }

  result_p->u.bigint_sign_and_size |= left_sign;
  return ecma_make_extended_primitive_value (result_p, ECMA_TYPE_BIGINT);
} /* ecma_bigint_shift */


ecma_deref_ecma_string_non_direct (ecma_string_t *string_p) /**< ecma-string */
{
  JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string_p));

#ifdef JERRY_NDEBUG
  if (ECMA_STRING_IS_STATIC (string_p))
  {
    return;
  }
#endif /* JERRY_NDEBUG */

  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);

  /* Decrease reference counter. */
  string_p->refs_and_container -= ECMA_STRING_REF_ONE;

  if (string_p->refs_and_container >= ECMA_STRING_REF_ONE)
  {
    return;
  }

  ecma_destroy_ecma_string (string_p);
} /* ecma_deref_ecma_string_non_direct */


parser_parse_do_while_statement_end (parser_context_t *context_p) /**< context */
{
  parser_loop_statement_t loop;

  JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_DO_WHILE);

  if (context_p->token.type != LEXER_KEYW_WHILE)
  {
    parser_raise_error (context_p, PARSER_ERR_WHILE_EXPECTED);
  }

  parser_stack_iterator_t iterator;
  parser_stack_iterator_init (context_p, &iterator);

  parser_stack_iterator_skip (&iterator, 1);
  parser_stack_iterator_read (&iterator, &loop, sizeof (parser_loop_statement_t));

  parser_set_continues_to_current_position (context_p, loop.branch_list_p);

  JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p);

  parser_parse_enclosed_expr (context_p);

  if (context_p->last_cbc_opcode != CBC_PUSH_FALSE)
  {
    cbc_opcode_t opcode = CBC_BRANCH_IF_TRUE_BACKWARD;
    if (context_p->last_cbc_opcode == CBC_LOGICAL_NOT)
    {
      context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
      opcode = CBC_BRANCH_IF_FALSE_BACKWARD;
    }
    else if (context_p->last_cbc_opcode == CBC_PUSH_TRUE)
    {
      context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
      opcode = CBC_JUMP_BACKWARD;
    }

    parser_do_while_statement_t do_while_statement;
    parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
    parser_stack_iterator_read (&iterator, &do_while_statement, sizeof (parser_do_while_statement_t));

    parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, do_while_statement.start_offset);
  }
  else
  {
    context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
  }

  parser_stack_pop (context_p, NULL, 1 + sizeof (parser_loop_statement_t) + sizeof (parser_do_while_statement_t));
  parser_stack_iterator_init (context_p, &context_p->last_statement);

  parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
} /* parser_parse_do_while_statement_end */


parser_append_object_literal_item (parser_context_t *context_p, /**< context */
                                   uint16_t item_index, /**< index of the item name */
                                   parser_object_literal_item_types_t item_type) /**< type of the item */
{
  parser_stack_iterator_t iterator;
  uint8_t *current_item_type_p;

  iterator.current_p = context_p->stack.first_p;
  iterator.current_position = context_p->stack.last_position;

  while (true)
  {
    current_item_type_p = iterator.current_p->bytes + iterator.current_position - 1;

    if (*current_item_type_p == PARSER_OBJECT_PROPERTY_START)
    {
      parser_stack_push_uint16 (context_p, item_index);
      parser_stack_push_uint8 (context_p, (uint8_t) item_type);
      return;
    }

    iterator.current_position--;
    if (iterator.current_position == 0)
    {
      iterator.current_p = iterator.current_p->next_p;
      iterator.current_position = PARSER_STACK_PAGE_SIZE;
    }

    uint32_t current_item_index = iterator.current_p->bytes[iterator.current_position - 1];

    iterator.current_position--;
    if (iterator.current_position == 0)
    {
      iterator.current_p = iterator.current_p->next_p;
      iterator.current_position = PARSER_STACK_PAGE_SIZE;
    }

    current_item_index |= ((uint32_t) iterator.current_p->bytes[iterator.current_position - 1]) << 8;

    iterator.current_position--;
    if (iterator.current_position == 0)
    {
      iterator.current_p = iterator.current_p->next_p;
      iterator.current_position = PARSER_STACK_PAGE_SIZE;
    }

    if (current_item_index == item_index)
    {
      if (item_type == PARSER_OBJECT_PROPERTY_VALUE
          && *current_item_type_p == PARSER_OBJECT_PROPERTY_VALUE
          && !(context_p->status_flags & PARSER_IS_STRICT))
      {
        return;
      }

      if (item_type == PARSER_OBJECT_PROPERTY_GETTER
          && *current_item_type_p == PARSER_OBJECT_PROPERTY_SETTER)
      {
        break;
      }

      if (item_type == PARSER_OBJECT_PROPERTY_SETTER
          && *current_item_type_p == PARSER_OBJECT_PROPERTY_GETTER)
      {
        break;
      }

      parser_raise_error (context_p, PARSER_ERR_OBJECT_PROPERTY_REDEFINED);
    }
  }

  uint8_t *last_page_p = context_p->stack.first_p->bytes;

  *current_item_type_p = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;

  if (current_item_type_p == (last_page_p + context_p->stack.last_position - 1))
  {
    context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;
  }
} /* parser_append_object_literal_item */


parser_append_breakpoint_info (parser_context_t *context_p, /**< context */
                               jerry_debugger_header_type_t type, /**< message type */
                               uint32_t value) /**< line or offset of the breakpoint */
{
  JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);

  context_p->status_flags |= PARSER_DEBUGGER_BREAKPOINT_APPENDED;

  if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_breakpoint_info_t))
  {
    parser_send_breakpoints (context_p, type);
  }

  context_p->breakpoint_info[context_p->breakpoint_info_count].value = value;
  context_p->breakpoint_info_count = (uint16_t) (context_p->breakpoint_info_count + 1);
} /* parser_append_breakpoint_info */


ecma_date_sec_from_time (ecma_number_t time) /**< time value */
{
  JERRY_ASSERT (!ecma_number_is_nan (time));

  int32_t time_in_day = ecma_date_time_in_day_from_time (time);

  return ((int32_t) (time_in_day / ECMA_DATE_MS_PER_SECOND)) % ECMA_DATE_SECONDS_PER_MINUTE;
} /* ecma_date_sec_from_time */


ecma_string_trim (const ecma_string_t *string_p) /**< pointer to an ecma string */
{
  ecma_string_t *ret_string_p;

  lit_utf8_size_t utf8_str_size;
  uint8_t flags = ECMA_STRING_FLAG_IS_ASCII;
  const lit_utf8_byte_t *utf8_str_p = ecma_string_get_chars (string_p, &utf8_str_size, NULL, NULL, &flags);

  if (utf8_str_size > 0)
  {
    ecma_string_trim_helper (&utf8_str_p, &utf8_str_size);
    ret_string_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, utf8_str_size);
  }
  else
  {
    ret_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY);
  }

  if (flags & ECMA_STRING_FLAG_MUST_BE_FREED)
  {
    jmem_heap_free_block ((void *) utf8_str_p, utf8_str_size);
  }

  return ret_string_p;
} /* ecma_string_trim */


scanner_append_hole (parser_context_t *context_p, scanner_context_t *scanner_context_p)
{
  scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;

  lexer_lit_location_t *literal_p;
  literal_p = (lexer_lit_location_t *) parser_list_append (context_p, &literal_pool_p->literal_pool);

  literal_p->char_p = NULL;
  literal_p->length = 0;
  literal_p->type = SCANNER_LITERAL_IS_ARG;
  literal_p->status_flags = LEXER_LIT_LOCATION_NO_OPTS;
} /* scanner_append_hole */


ecma_date_local_time_zone_adjustment (ecma_number_t time) /**< time value */
{
  return jerry_port_get_local_time_zone_adjustment (time, true);
} /* ecma_date_local_time_zone_adjustment */


parser_parse_default_statement (parser_context_t *context_p) /**< context */
{
  parser_stack_iterator_t iterator;
  parser_switch_statement_t switch_statement;

  if (context_p->stack_top_uint8 != PARSER_STATEMENT_SWITCH
      && context_p->stack_top_uint8 != PARSER_STATEMENT_SWITCH_NO_DEFAULT)
  {
    parser_raise_error (context_p, PARSER_ERR_DEFAULT_NOT_IN_SWITCH);
  }

  lexer_next_token (context_p);
  /* Already checked in parser_parse_switch_statement_start. */
  JERRY_ASSERT (context_p->token.type == LEXER_COLON);
  lexer_next_token (context_p);

  parser_stack_iterator_init (context_p, &iterator);
  parser_stack_iterator_skip (&iterator, 1 + sizeof (parser_loop_statement_t));
  parser_stack_iterator_read (&iterator, &switch_statement, sizeof (parser_switch_statement_t));

  parser_set_branch_to_current_position (context_p, &switch_statement.default_branch);
} /* parser_parse_default_statement */


parser_print_literal (parser_context_t *context_p, /**< context */
                      uint16_t literal_index) /**< index of literal */
{
  parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p;
  parser_scope_stack_t *scope_stack_end_p = scope_stack_p + context_p->scope_stack_top;
  bool in_scope_literal = false;

  while (scope_stack_p < scope_stack_end_p)
  {
    scope_stack_end_p--;

    if (scope_stack_end_p->map_from == PARSER_SCOPE_STACK_FUNC)
    {
      if (literal_index == scope_stack_end_p->map_to)
      {
        in_scope_literal = true;
        break;
      }
    }
    else if (literal_index == scanner_decode_map_to (scope_stack_end_p))
    {
      in_scope_literal = true;
      break;
    }
  }

  if (literal_index < PARSER_REGISTER_START)
  {
    JERRY_DEBUG_MSG (in_scope_literal ? " IDX:%d->" : " idx:%d->", literal_index);
    lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
    util_print_literal (literal_p);
    return;
  }

  if (!in_scope_literal)
  {
    JERRY_DEBUG_MSG (" reg:%d", (int) (literal_index - PARSER_REGISTER_START));
    return;
  }

  JERRY_DEBUG_MSG (" REG:%d->", (int) (literal_index - PARSER_REGISTER_START));

  lexer_literal_t *literal_p = PARSER_GET_LITERAL (scope_stack_end_p->map_from);
  util_print_literal (literal_p);
} /* parser_print_literal */


scanner_add_reference (parser_context_t *context_p, /**< context */
                       scanner_context_t *scanner_context_p) /**< scanner context */
{
  lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p,
                                                                     scanner_context_p->active_literal_pool_p,
                                                                     &context_p->token.lit_location);
#if JERRY_ESNEXT
  lit_location_p->type |= SCANNER_LITERAL_IS_USED;
#endif /* JERRY_ESNEXT */

  if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
  {
    lit_location_p->type |= SCANNER_LITERAL_NO_REG;
  }

  scanner_detect_eval_call (context_p, scanner_context_p);
} /* scanner_add_reference */


ecma_stringbuilder_destroy (ecma_stringbuilder_t *builder_p) /**< string builder */
{
  JERRY_ASSERT (builder_p->header_p != NULL);
  const lit_utf8_size_t size = builder_p->header_p->current_size;
  jmem_heap_free_block (builder_p->header_p, size);

#ifndef JERRY_NDEBUG
  builder_p->header_p = NULL;
#endif

#if JERRY_MEM_STATS
  jmem_stats_free_string_bytes (size);
#endif /* JERRY_MEM_STATS */
} /* ecma_stringbuilder_destroy */


parser_statement_length (uint8_t type) /**< type of statement */
{
  static const uint8_t statement_lengths[] =
  {
    /* PARSER_STATEMENT_BLOCK */
    1,
#if JERRY_ESNEXT
    /* PARSER_STATEMENT_BLOCK_SCOPE */
    (uint8_t) (sizeof (parser_block_statement_t) + 1),
    /* PARSER_STATEMENT_PRIVATE_SCOPE */
    (uint8_t) (sizeof (parser_block_statement_t) + 1),
    /* PARSER_STATEMENT_BLOCK_CONTEXT */
    (uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1),
    /* PARSER_STATEMENT_PRIVATE_CONTEXT */
    (uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1),
#endif /* JERRY_ESNEXT */
    /* PARSER_STATEMENT_LABEL */
    (uint8_t) (sizeof (parser_label_statement_t) + 1),
    /* PARSER_STATEMENT_IF */
    (uint8_t) (sizeof (parser_if_else_statement_t) + 1),
    /* PARSER_STATEMENT_ELSE */
    (uint8_t) (sizeof (parser_if_else_statement_t) + 1),
    /* PARSER_STATEMENT_SWITCH */
    (uint8_t) (sizeof (parser_switch_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_SWITCH_NO_DEFAULT */
    (uint8_t) (sizeof (parser_switch_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_DO_WHILE */
    (uint8_t) (sizeof (parser_do_while_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_WHILE */
    (uint8_t) (sizeof (parser_while_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_FOR */
    (uint8_t) (sizeof (parser_for_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_FOR_IN */
    (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
#if JERRY_ESNEXT
    /* PARSER_STATEMENT_FOR_OF */
    (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
    /* PARSER_STATEMENT_FOR_AWAIT_OF */
    (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
#endif /* JERRY_ESNEXT */
    /* PARSER_STATEMENT_WITH */
    (uint8_t) (sizeof (parser_with_statement_t) + 1 + 1),
    /* PARSER_STATEMENT_TRY */
    (uint8_t) (sizeof (parser_try_statement_t) + 1),
  };

  JERRY_ASSERT (type >= PARSER_STATEMENT_BLOCK && type <= PARSER_STATEMENT_TRY);

  return statement_lengths[type - PARSER_STATEMENT_BLOCK];
} /* parser_statement_length */


parser_parse_object_initializer (parser_context_t *context_p, /**< context */
                                 parser_pattern_flags_t flags) /**< flags */
{
  parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags);

  /* 12.14.5.2:  ObjectAssignmentPattern : { } */
  if (lexer_check_next_character (context_p, LIT_CHAR_RIGHT_BRACE))
  {
    parser_emit_cbc_ext (context_p, CBC_EXT_REQUIRE_OBJECT_COERCIBLE);
    lexer_consume_next_character (context_p);
    parser_pattern_finalize (context_p, flags, &end_pos);
    return;
  }

  cbc_ext_opcode_t context_opcode = CBC_EXT_OBJ_INIT_CONTEXT_CREATE;

  if (flags & PARSER_PATTERN_HAS_REST_ELEMENT)
  {
    context_opcode = CBC_EXT_OBJ_INIT_REST_CONTEXT_CREATE;
  }

  parser_emit_cbc_ext (context_p, context_opcode);

  while (true)
  {
    lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJECT_PATTERN);

    uint16_t prop_index = context_p->lit_object.index;
    parser_line_counter_t start_line = context_p->token.line;
    parser_line_counter_t start_column = context_p->token.column;
    uint16_t push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP_LITERAL;

    if (context_p->token.type == LEXER_RIGHT_BRACE)
    {
      break;
    }

    if (context_p->token.type == LEXER_THREE_DOTS)
    {
      lexer_next_token (context_p);

      flags |= PARSER_PATTERN_REST_ELEMENT;

      if (parser_pattern_process_assignment (context_p,
                                             flags,
                                             CBC_EXT_OBJ_INIT_PUSH_REST,
                                             PARSER_PATTERN_RHS_NO_LIT,
                                             LEXER_RIGHT_BRACE))
      {
        parser_raise_error (context_p, PARSER_ERR_INVALID_LHS_ASSIGNMENT);
      }

      if (context_p->token.type != LEXER_RIGHT_BRACE)
      {
        parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
      }

      /* Checked at the end because there might be syntax errors before. */
      JERRY_ASSERT (flags & PARSER_PATTERN_HAS_REST_ELEMENT);
      break;
    }

    if (context_p->token.type == LEXER_RIGHT_SQUARE)
    {
      prop_index = PARSER_PATTERN_RHS_NO_LIT;
      push_prop_opcode = ((flags & PARSER_PATTERN_HAS_REST_ELEMENT) ? CBC_EXT_INITIALIZER_PUSH_NAME
                                                                    : CBC_EXT_INITIALIZER_PUSH_PROP);
    }
    else if (flags & PARSER_PATTERN_HAS_REST_ELEMENT)
    {
      push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_NAME_LITERAL;
    }

    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
      parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
    }

    lexer_next_token (context_p);

    if (context_p->token.type == LEXER_COLON)
    {
      lexer_next_token (context_p);
      parser_pattern_process_assignment (context_p, flags, push_prop_opcode, prop_index, LEXER_RIGHT_BRACE);
    }
    else
    {
      if (push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_NAME
          || push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_PROP)
      {
        parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
      }

      if (context_p->token.type != LEXER_RIGHT_BRACE
          && context_p->token.type != LEXER_ASSIGN
          && context_p->token.type != LEXER_COMMA)
      {
        parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
      }

      parser_reparse_as_common_identifier (context_p, start_line, start_column);

      if (flags & PARSER_PATTERN_ARGUMENTS)
      {
        if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
        {
          parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
        }
        context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT;
      }

#if JERRY_MODULE_SYSTEM
      parser_module_append_export_name (context_p);
#endif /* JERRY_MODULE_SYSTEM */

      parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);

      lexer_next_token (context_p);
      JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE
                    || context_p->token.type == LEXER_ASSIGN
                    || context_p->token.type == LEXER_COMMA);

      parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line);
#if JERRY_LINE_INFO
      parser_line_info_append (context_p, start_line, start_column);
#endif /* JERRY_LINE_INFO */
    }

    if (context_p->token.type == LEXER_RIGHT_BRACE)
    {
      break;
    }
    else if (context_p->token.type != LEXER_COMMA)
    {
      parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
    }
  }

  if (flags & PARSER_PATTERN_HAS_REST_ELEMENT)
  {
    PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, (PARSER_OBJ_INIT_REST_CONTEXT_STACK_ALLOCATION
                                                     - PARSER_OBJ_INIT_CONTEXT_STACK_ALLOCATION));
  }

  parser_emit_cbc_ext (context_p, CBC_EXT_OBJ_INIT_CONTEXT_END);

  parser_pattern_finalize (context_p, flags, &end_pos);
} /* parser_parse_object_initializer */


ecma_string_get_ascii_size (const ecma_string_t *string_p) /**< ecma-string */
{
  if (ECMA_IS_DIRECT_STRING (string_p))
  {
    switch (ECMA_GET_DIRECT_STRING_TYPE (string_p))
    {
      case ECMA_DIRECT_STRING_MAGIC:
      {
        uint32_t id = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);

        if (id >= LIT_MAGIC_STRING__COUNT)
        {
          return ECMA_STRING_NO_ASCII_SIZE;
        }

        JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (id),
                                            lit_get_magic_string_size (id)));

        return lit_get_magic_string_size (id);
      }
      default:
      {
        JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_UINT);
        uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p);
        return ecma_string_get_uint32_size (uint32_number);
      }
    }
  }

  JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE);

  if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC)
  {
    return ecma_string_get_uint32_size (string_p->u.uint32_number);
  }
  else if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_HEAP_ASCII_STRING)
  {
    return ECMA_ASCII_STRING_GET_SIZE (string_p);
  }

  return ECMA_STRING_NO_ASCII_SIZE;
} /* ecma_string_get_ascii_size */


ecma_stringbuilder_finalize (ecma_stringbuilder_t *builder_p) /**< string builder */
{
  ecma_stringbuilder_header_t *header_p = builder_p->header_p;
  JERRY_ASSERT (header_p != NULL);

  const lit_utf8_size_t string_size = ECMA_STRINGBUILDER_STRING_SIZE (header_p);
  lit_utf8_byte_t *string_begin_p = ECMA_STRINGBUILDER_STRING_PTR (header_p);

  ecma_string_t *string_p = ecma_find_special_string (string_begin_p, string_size);

  if (JERRY_UNLIKELY (string_p != NULL))
  {
    ecma_stringbuilder_destroy (builder_p);
    return string_p;
  }

#ifndef JERRY_NDEBUG
  builder_p->header_p = NULL;
#endif

  size_t container_size = sizeof (ecma_short_string_t);
  const lit_string_hash_t hash = lit_utf8_string_calc_hash (string_begin_p, string_size);
  const lit_utf8_size_t length = lit_utf8_string_length (string_begin_p, string_size);

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    if (JERRY_LIKELY (length == string_size) && string_size <= (UINT8_MAX + 1))
    {
      string_p = (ecma_string_t *) header_p;
      string_p->refs_and_container = ECMA_STRING_CONTAINER_HEAP_ASCII_STRING | ECMA_STRING_REF_ONE;
      string_p->u.hash = hash;
      ECMA_ASCII_STRING_SET_SIZE (string_p, string_size);

      return (ecma_string_t *) string_p;
    }
  }
  else
  {
    container_size = sizeof (ecma_long_string_t);
  }

  const size_t utf8_string_size = string_size + container_size;
  header_p = jmem_heap_realloc_block (header_p, header_p->current_size, utf8_string_size);
  memmove (((lit_utf8_byte_t *) header_p + container_size),
           ECMA_STRINGBUILDER_STRING_PTR (header_p),
           string_size);

#if JERRY_MEM_STATS
  jmem_stats_allocate_string_bytes (container_size - ECMA_ASCII_STRING_HEADER_SIZE);
#endif /* JERRY_MEM_STATS */

  if (JERRY_LIKELY (string_size <= UINT16_MAX))
  {
    ecma_short_string_t *short_string_p = (ecma_short_string_t *) header_p;

    short_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_HEAP_UTF8_STRING | ECMA_STRING_REF_ONE;
    short_string_p->header.u.hash = hash;
    short_string_p->size = (uint16_t) string_size;
    short_string_p->length = (uint16_t) length;

    return (ecma_string_t *) short_string_p;
  }

  ecma_long_string_t *long_string_p = (ecma_long_string_t *) header_p;

  long_string_p->header.refs_and_container = ECMA_STRING_CONTAINER_LONG_OR_EXTERNAL_STRING | ECMA_STRING_REF_ONE;
  long_string_p->header.u.hash = hash;
  long_string_p->string_p = ECMA_LONG_STRING_BUFFER_START (long_string_p);
  long_string_p->size = string_size;
  long_string_p->length = length;

  return (ecma_string_t *) long_string_p;
} /* ecma_stringbuilder_finalize */


parser_emit_cbc_forward_branch (parser_context_t *context_p, /**< context */
                                uint16_t opcode, /**< opcode */
                                parser_branch_t *branch_p) /**< branch result */
{
  uint8_t flags;
  uint32_t extra_byte_code_increase;

  if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
  {
    parser_flush_cbc (context_p);
  }

  context_p->status_flags |= PARSER_NO_END_LABEL;

  if (PARSER_IS_BASIC_OPCODE (opcode))
  {
    JERRY_ASSERT (opcode < CBC_END);
    flags = cbc_flags[opcode];
    extra_byte_code_increase = 0;
  }
  else
  {
    PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
    opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);

    JERRY_ASSERT (opcode < CBC_EXT_END);
    flags = cbc_ext_flags[opcode];
    extra_byte_code_increase = 1;
  }

  JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
  JERRY_ASSERT (CBC_BRANCH_IS_FORWARD (flags));
  JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);

  /* Branch opcodes never push anything onto the stack. */
  JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
                 || (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
  PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));

#if JERRY_PARSER_DUMP_BYTE_CODE
  if (context_p->is_show_opcodes)
  {
    JERRY_DEBUG_MSG ("  [%3d] %s\n",
                     (int) context_p->stack_depth,
                     extra_byte_code_increase == 0 ? cbc_names[opcode] : cbc_ext_names[opcode]);
  }
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */

  PARSER_PLUS_EQUAL_U16 (opcode, PARSER_MAX_BRANCH_LENGTH - 1);

  parser_emit_two_bytes (context_p, (uint8_t) opcode, 0);
  branch_p->page_p = context_p->byte_code.last_p;
  branch_p->offset = (context_p->byte_code.last_position - 1) | (context_p->byte_code_size << 8);

  context_p->byte_code_size += extra_byte_code_increase;

#if PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX
  PARSER_APPEND_TO_BYTE_CODE (context_p, 0);
#else /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */
  parser_emit_two_bytes (context_p, 0, 0);
#endif /* PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX */

  context_p->byte_code_size += PARSER_MAX_BRANCH_LENGTH + 1;

  if (context_p->stack_depth > context_p->stack_limit)
  {
    context_p->stack_limit = context_p->stack_depth;
    if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
    {
      parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
    }
  }
} /* parser_emit_cbc_forward_branch */


scanner_detect_eval_call (parser_context_t *context_p, /**< context */
                          scanner_context_t *scanner_context_p) /**< scanner context */
{
  if (context_p->token.keyword_type == LEXER_KEYW_EVAL
      && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
  {
#if JERRY_ESNEXT
    const uint16_t flags = (uint16_t) (SCANNER_LITERAL_POOL_CAN_EVAL | SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE);
#else /* !JERRY_ESNEXT */
    const uint16_t flags = SCANNER_LITERAL_POOL_CAN_EVAL;
#endif /* JERRY_ESNEXT */

    scanner_context_p->active_literal_pool_p->status_flags |= flags;
  }
} /* scanner_detect_eval_call */


parser_emit_cbc_backward_branch (parser_context_t *context_p, /**< context */
                                 uint16_t opcode, /**< opcode */
                                 uint32_t offset) /**< destination offset */
{
  uint8_t flags;
#if JERRY_PARSER_DUMP_BYTE_CODE
  const char *name;
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */

  if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
  {
    parser_flush_cbc (context_p);
  }

  context_p->status_flags |= PARSER_NO_END_LABEL;
  offset = context_p->byte_code_size - offset;

  if (PARSER_IS_BASIC_OPCODE (opcode))
  {
    JERRY_ASSERT (opcode < CBC_END);
    flags = cbc_flags[opcode];

#if JERRY_PARSER_DUMP_BYTE_CODE
    name = cbc_names[opcode];
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
  }
  else
  {
    PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
    opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);

    JERRY_ASSERT (opcode < CBC_EXT_END);
    flags = cbc_ext_flags[opcode];
    context_p->byte_code_size++;

#if JERRY_PARSER_DUMP_BYTE_CODE
    name = cbc_ext_names[opcode];
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
  }

  JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
  JERRY_ASSERT (CBC_BRANCH_IS_BACKWARD (flags));
  JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);
  JERRY_ASSERT (offset <= context_p->byte_code_size);

  /* Branch opcodes never push anything onto the stack. */
  JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
                 || (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
  PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));

#if JERRY_PARSER_DUMP_BYTE_CODE
  if (context_p->is_show_opcodes)
  {
    JERRY_DEBUG_MSG ("  [%3d] %s\n", (int) context_p->stack_depth, name);
  }
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */

  context_p->byte_code_size += 2;
#if PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX
  if (offset > UINT16_MAX)
  {
    opcode++;
    context_p->byte_code_size++;
  }
#endif /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */

  if (offset > UINT8_MAX)
  {
    opcode++;
    context_p->byte_code_size++;
  }

  PARSER_APPEND_TO_BYTE_CODE (context_p, (uint8_t) opcode);

#if PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX
  if (offset > UINT16_MAX)
  {
    PARSER_APPEND_TO_BYTE_CODE (context_p, offset >> 16);
  }
#endif /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */

  if (offset > UINT8_MAX)
  {
    PARSER_APPEND_TO_BYTE_CODE (context_p, (offset >> 8) & 0xff);
  }

  PARSER_APPEND_TO_BYTE_CODE (context_p, offset & 0xff);
} /* parser_emit_cbc_backward_branch */


lexer_convert_push_number_to_push_literal (parser_context_t *context_p) /**< context */
{
  ecma_integer_value_t value;
  bool two_literals = context_p->last_cbc_opcode >= CBC_PUSH_LITERAL_PUSH_NUMBER_0;

  if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_0
      || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_0)
  {
    value = 0;
  }
  else if (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_POS_BYTE
           || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_POS_BYTE)
  {
    value = ((ecma_integer_value_t) context_p->last_cbc.value) + 1;
  }
  else
  {
    JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_NUMBER_NEG_BYTE
                  || context_p->last_cbc_opcode == CBC_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE);
    value = -((ecma_integer_value_t) context_p->last_cbc.value) - 1;
  }

  ecma_value_t lit_value = ecma_make_integer_value (value);

  parser_list_iterator_t literal_iterator;
  parser_list_iterator_init (&context_p->literal_pool, &literal_iterator);

  context_p->last_cbc_opcode = two_literals ? CBC_PUSH_TWO_LITERALS : CBC_PUSH_LITERAL;

  uint32_t literal_index = 0;
  lexer_literal_t *literal_p;

  while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL)
  {
    if (literal_p->type == LEXER_NUMBER_LITERAL
        && literal_p->u.value == lit_value)
    {
      if (two_literals)
      {
        context_p->last_cbc.value = (uint16_t) literal_index;
      }
      else
      {
        context_p->last_cbc.literal_index = (uint16_t) literal_index;
      }
      return;
    }

    literal_index++;
  }

  JERRY_ASSERT (literal_index == context_p->literal_count);

  if (literal_index >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
  {
    parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
  }

  literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
  literal_p->u.value = lit_value;
  literal_p->prop.length = 0; /* Unused. */
  literal_p->type = LEXER_NUMBER_LITERAL;
  literal_p->status_flags = 0;

  context_p->literal_count++;

  if (two_literals)
  {
    context_p->last_cbc.value = (uint16_t) literal_index;
  }
  else
  {
    context_p->last_cbc.literal_index = (uint16_t) literal_index;
  }
} /* lexer_convert_push_number_to_push_literal */


ecma_stringbuilder_create_raw (const lit_utf8_byte_t *data_p, /**< pointer to data */
                               const lit_utf8_size_t data_size) /**< size of the data */
{
  const lit_utf8_size_t initial_size = data_size + ECMA_ASCII_STRING_HEADER_SIZE;

  ecma_stringbuilder_header_t *header_p = (ecma_stringbuilder_header_t *) jmem_heap_alloc_block (initial_size);
  header_p->current_size = initial_size;
#if JERRY_MEM_STATS
  jmem_stats_allocate_string_bytes (initial_size);
#endif /* JERRY_MEM_STATS */

  memcpy (ECMA_STRINGBUILDER_STRING_PTR (header_p), data_p, data_size);

  ecma_stringbuilder_t ret = {.header_p = header_p};
  return ret;
} /* ecma_stringbuilder_create_raw */


ecma_date_month_from_time (ecma_number_t time) /**< time value */
{
  JERRY_ASSERT (!ecma_number_is_nan (time));

  int32_t year = ecma_date_year_from_time (time);
  int32_t day_within_year = ecma_date_day_from_time (time) - ecma_date_day_from_year (year);

  JERRY_ASSERT (day_within_year >= 0 && day_within_year < ECMA_DATE_DAYS_IN_LEAP_YEAR);

  int32_t in_leap_year = ecma_date_in_leap_year (year);

  for (int i = 1; i < 12; i++)
  {
    if (day_within_year < first_day_in_month[in_leap_year][i])
    {
      return i - 1;
    }
  }

  return 11;
} /* ecma_date_month_from_time */


static av_always_inline void put_padding(PutBitContext *pb, int bytes)
{
    int bits = bytes*8;
    if (!bits)
        return;
    while (bits > 31) {
        put_bits(pb, 31, 0);
        bits -= 31;
    }
    if (bits)
        put_bits(pb, bits, 0);
}


/* VC-2 13.5.3 - hq_slice */
static int encode_hq_slice(AVCodecContext *avctx, void *arg)
{
    SliceArgs *slice_dat = arg;
    VC2EncContext *s = slice_dat->ctx;
    PutBitContext *pb = &slice_dat->pb;
    const int slice_x = slice_dat->x;
    const int slice_y = slice_dat->y;
    const int quant_idx = slice_dat->quant_idx;
    const int slice_bytes_max = slice_dat->bytes;
    uint8_t quants[MAX_DWT_LEVELS][4];
    int p, level, orientation;

    avpriv_align_put_bits(pb);
    put_padding(pb, s->prefix_bytes);
    put_bits(pb, 8, quant_idx);

    /* Slice quantization (slice_quantizers() in the specs) */
    for (level = 0; level < s->wavelet_depth; level++)
        for (orientation = !!level; orientation < 4; orientation++)
            quants[level][orientation] = FFMAX(quant_idx - s->quant[level][orientation], 0);

    /* Luma + 2 Chroma planes */
    for (p = 0; p < 3; p++) {
        int bytes_start, bytes_len, pad_s, pad_c;
        bytes_start = put_bits_count(pb) >> 3;
        put_bits(pb, 8, 0);
        for (level = 0; level < s->wavelet_depth; level++) {
            for (orientation = !!level; orientation < 4; orientation++) {
                encode_subband(s, pb, slice_x, slice_y,
                               &s->plane[p].band[level][orientation],
                               quants[level][orientation]);
            }
        }
        avpriv_align_put_bits(pb);
        bytes_len = (put_bits_count(pb) >> 3) - bytes_start - 1;
        if (p == 2) {
            int len_diff = slice_bytes_max - (put_bits_count(pb) >> 3);
            pad_s = FFALIGN((bytes_len + len_diff), s->size_scaler)/s->size_scaler;
            pad_c = (pad_s*s->size_scaler) - bytes_len;
        } else {
            pad_s = FFALIGN(bytes_len, s->size_scaler)/s->size_scaler;
            pad_c = (pad_s*s->size_scaler) - bytes_len;
        }
        pb->buf[bytes_start] = pad_s;
        put_padding(pb, pad_c);
    }

    return 0;


static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
{
    int code, value, ofs = 0;
    char layout[16] = {0}; /* not for printing, may end up not terminated on purpose */

    do {
        code = avio_r8(pb);
        value = avio_r8(pb);
        av_dlog(NULL, "pixel layout: code %#x\n", code);

        if (ofs <= 14) {
            layout[ofs++] = code;
            layout[ofs++] = value;
        } else
            break;  /* don't read byte by byte on sneaky files filled with lots of non-zeroes */
    } while (code != 0); /* SMPTE 377M E.2.46 */

    ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);
}


static int mxf_compute_index_tables(MXFContext *mxf)
{
    int i, j, k, ret, nb_sorted_segments;
    MXFIndexTableSegment **sorted_segments = NULL;

    if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) ||
        nb_sorted_segments <= 0) {
        av_log(mxf->fc, AV_LOG_WARNING, "broken or empty index\n");
        return 0;
    }

    /* sanity check and count unique BodySIDs/IndexSIDs */
    for (i = 0; i < nb_sorted_segments; i++) {
        if (i == 0 || sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid)
            mxf->nb_index_tables++;
        else if (sorted_segments[i-1]->body_sid != sorted_segments[i]->body_sid) {
            av_log(mxf->fc, AV_LOG_ERROR, "found inconsistent BodySID\n");
            ret = AVERROR_INVALIDDATA;
            goto finish_decoding_index;
        }
    }

    mxf->index_tables = av_mallocz_array(mxf->nb_index_tables,
                                         sizeof(*mxf->index_tables));
    if (!mxf->index_tables) {
        av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate index tables\n");
        ret = AVERROR(ENOMEM);
        goto finish_decoding_index;
    }

    /* distribute sorted segments to index tables */
    for (i = j = 0; i < nb_sorted_segments; i++) {
        if (i != 0 && sorted_segments[i-1]->index_sid != sorted_segments[i]->index_sid) {
            /* next IndexSID */
            j++;
        }

        mxf->index_tables[j].nb_segments++;
    }

    for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) {
        MXFIndexTable *t = &mxf->index_tables[j];

        t->segments = av_mallocz_array(t->nb_segments,
                                       sizeof(*t->segments));

        if (!t->segments) {
            av_log(mxf->fc, AV_LOG_ERROR, "failed to allocate IndexTableSegment"
                   " pointer array\n");
            ret = AVERROR(ENOMEM);
            goto finish_decoding_index;
        }

        if (sorted_segments[i]->index_start_position)
            av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i starts at EditUnit %"PRId64" - seeking may not work as expected\n",
                   sorted_segments[i]->index_sid, sorted_segments[i]->index_start_position);

        memcpy(t->segments, &sorted_segments[i], t->nb_segments * sizeof(MXFIndexTableSegment*));
        t->index_sid = sorted_segments[i]->index_sid;
        t->body_sid = sorted_segments[i]->body_sid;

        if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0)
            goto finish_decoding_index;

        /* fix zero IndexDurations */
        for (k = 0; k < t->nb_segments; k++) {
            if (t->segments[k]->index_duration)
                continue;

            if (t->nb_segments > 1)
                av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has zero IndexDuration and there's more than one segment\n",
                       t->index_sid, k);

            if (mxf->fc->nb_streams <= 0) {
                av_log(mxf->fc, AV_LOG_WARNING, "no streams?\n");
                break;
            }

            /* assume the first stream's duration is reasonable
             * leave index_duration = 0 on further segments in case we have any (unlikely)
             */
            t->segments[k]->index_duration = mxf->fc->streams[0]->duration;
            break;
        }
    }

    ret = 0;
finish_decoding_index:
    av_free(sorted_segments);
    return ret;
}


void ass_expand_horz_c(int16_t *dst, const int16_t *src,
                       uintptr_t src_width, uintptr_t src_height)
{
    uintptr_t dst_width = 2 * src_width + 4;
    uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
    uintptr_t step = STRIPE_WIDTH * src_height;

    uintptr_t offs = 0;
    int16_t buf[2 * STRIPE_WIDTH];
    int16_t *ptr = buf + STRIPE_WIDTH;
    for (uintptr_t x = STRIPE_WIDTH; x < dst_width; x += 2 * STRIPE_WIDTH) {
        for (uintptr_t y = 0; y < src_height; ++y) {
            copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
            copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
            for (int k = 0; k < STRIPE_WIDTH / 2; ++k)
                expand_func(&dst[2 * k], &dst[2 * k + 1],
                            ptr[k - 2], ptr[k - 1], ptr[k]);
            int16_t *next = dst + step - STRIPE_WIDTH;
            for (int k = STRIPE_WIDTH / 2; k < STRIPE_WIDTH; ++k)
                expand_func(&next[2 * k], &next[2 * k + 1],
                            ptr[k - 2], ptr[k - 1], ptr[k]);
            dst += STRIPE_WIDTH;
            offs += STRIPE_WIDTH;
        }
        dst += step;
    }
    if ((dst_width - 1) & STRIPE_WIDTH)
        return;

    for (uintptr_t y = 0; y < src_height; ++y) {
        copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
        copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
        for (int k = 0; k < STRIPE_WIDTH / 2; ++k)
            expand_func(&dst[2 * k], &dst[2 * k + 1],
                        ptr[k - 2], ptr[k - 1], ptr[k]);
        dst += STRIPE_WIDTH;
        offs += STRIPE_WIDTH;
    }
}


void ass_blur1234_horz_c(int16_t *dst, const int16_t *src,
                         uintptr_t src_width, uintptr_t src_height,
                         const int16_t *param)
{
    uintptr_t dst_width = src_width + 8;
    uintptr_t size = ((src_width + STRIPE_MASK) & ~STRIPE_MASK) * src_height;
    uintptr_t step = STRIPE_WIDTH * src_height;

    uintptr_t offs = 0;
    int16_t buf[2 * STRIPE_WIDTH];
    int16_t *ptr = buf + STRIPE_WIDTH;
    for (uintptr_t x = 0; x < dst_width; x += STRIPE_WIDTH) {
        for (uintptr_t y = 0; y < src_height; ++y) {
            copy_line(ptr - 1 * STRIPE_WIDTH, src, offs - 1 * step, size);
            copy_line(ptr - 0 * STRIPE_WIDTH, src, offs - 0 * step, size);
            for (int k = 0; k < STRIPE_WIDTH; ++k)
                dst[k] = blur_func(ptr[k - 8], ptr[k - 7], ptr[k - 6], ptr[k - 5], ptr[k - 4],
                                   ptr[k - 3], ptr[k - 2], ptr[k - 1], ptr[k - 0], param);
            dst += STRIPE_WIDTH;
            offs += STRIPE_WIDTH;
        }
    }
}


static int create_response_ietf_00(handler_ctx *hctx) {
    request_st * const r = hctx->gw.r;

    /* "Origin" header is preferred
     * ("Sec-WebSocket-Origin" is from older drafts of websocket spec) */
    const buffer *origin = http_header_request_get(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Origin"));
    if (NULL == origin) {
        origin =
          http_header_request_get(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Sec-WebSocket-Origin"));
    }
    if (NULL == origin) {
        DEBUG_LOG_ERR("%s", "Origin header is invalid");
        return -1;
    }
    if (!r->http_host || buffer_is_blank(r->http_host)) {
        DEBUG_LOG_ERR("%s", "Host header does not exist");
        return -1;
    }

    /* calc MD5 sum from keys */
    if (create_MD5_sum(r) < 0) {
        DEBUG_LOG_ERR("%s", "Sec-WebSocket-Key is invalid");
        return -1;
    }

    http_header_response_set(r, HTTP_HEADER_UPGRADE,
                             CONST_STR_LEN("Upgrade"),
                             CONST_STR_LEN("websocket"));
  #if 0 /*(added later in http_response_write_header())*/
    http_header_response_append(r, HTTP_HEADER_CONNECTION,
                                CONST_STR_LEN("Connection"),
                                CONST_STR_LEN("upgrade"));
  #endif
  #if 0 /*(Sec-WebSocket-Origin header is not required for hybi-00)*/
    /* Note: it is insecure to simply reflect back origin provided by client
     * (if admin did not configure restricted list of valid origins)
     * (see wstunnel_check_request()) */
    http_header_response_set(r, HTTP_HEADER_OTHER,
                             CONST_STR_LEN("Sec-WebSocket-Origin"),
                             BUF_PTR_LEN(origin));
  #endif

    buffer * const value =
      http_header_response_set_ptr(r, HTTP_HEADER_OTHER,
                                   CONST_STR_LEN("Sec-WebSocket-Location"));
    if (buffer_is_equal_string(&r->uri.scheme, CONST_STR_LEN("https")))
        buffer_copy_string_len(value, CONST_STR_LEN("wss://"));
    else
        buffer_copy_string_len(value, CONST_STR_LEN("ws://"));
    buffer_append_str2(value, BUF_PTR_LEN(r->http_host),
                              BUF_PTR_LEN(&r->uri.path));
    return 0;
}


static handler_t wstunnel_create_env(gw_handler_ctx *gwhctx) {
    handler_ctx *hctx = (handler_ctx *)gwhctx;
    request_st * const r = hctx->gw.r;
    handler_t rc;
    if (0 == r->reqbody_length || r->http_version > HTTP_VERSION_1_1) {
        http_response_upgrade_read_body_unknown(r);
        chunkqueue_append_chunkqueue(&r->reqbody_queue, &r->read_queue);
    }
    rc = mod_wstunnel_handshake_create_response(hctx);
    if (rc != HANDLER_GO_ON) return rc;

    r->http_status = (r->http_version > HTTP_VERSION_1_1)
      ? 200  /* OK (response status for CONNECT) */
      : 101; /* Switching Protocols */
    r->resp_body_started = 1;

    hctx->ping_ts = log_monotonic_secs;
    gw_set_transparent(&hctx->gw);

    return HANDLER_GO_ON;
}