From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 12757 invoked by alias); 9 Oct 2011 19:43:45 -0000 Received: (qmail 12620 invoked by uid 22791); 9 Oct 2011 19:43:41 -0000 X-SWARE-Spam-Status: No, hits=-2.1 required=5.0 tests=AWL,BAYES_00,RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from beast.archeia.com (HELO beast.archeia.com) (74.207.226.235) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 09 Oct 2011 19:43:21 +0000 Received: from [192.168.0.2] (5ac2a2db.bb.sky.com [90.194.162.219]) (Authenticated sender: laguest) by beast.archeia.com (Postfix) with ESMTPSA id 00AAF803F for ; Sun, 9 Oct 2011 19:43:19 +0000 (UTC) Subject: ARM EABI ZCX Ada (4.6.1) almost working From: "Luke A. Guest" To: GCC ML In-Reply-To: <1318159997.2808.28.camel@rogue> References: <1318159997.2808.28.camel@rogue> Content-Type: multipart/mixed; boundary="=-JleFCquO1Mh6Hrl6A7Mh" Date: Mon, 10 Oct 2011 05:08:00 -0000 Message-ID: <1318189083.26212.64.camel@rogue> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-owner@gcc.gnu.org X-SW-Source: 2011-10/txt/msg00156.txt.bz2 --=-JleFCquO1Mh6Hrl6A7Mh Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 854 Hi, I managed to debug the my sample app and find an error, which has made catching an exception work. Anyway, I changed the code to throw an exception in a nested subprogram, this was also caught by the outer subprogram. I then added a raise; statement as a handler to see if it would reraise and then exit the program, sadly, I get an infinite loop in the search phase (export EH_DEBUG=1 shows this). I've included the latest patch which gets the basics working. But I'm lost as to why it's not working for the reraise case. Can anyone help? Thanks, Luke. ** Just for info, so it's documented somewhere ** Just for people who need to know (as I couldn't find it anywhere), to get gnatlib to build with debugging info, I used the following: make -e GNATLIBCFLAGS='-ggdb -O0' This is then picked up the gcc/ada makefiles later in the build. --=-JleFCquO1Mh6Hrl6A7Mh Content-Disposition: attachment; filename="arm-linux-zcx.diff" Content-Type: text/x-patch; name="arm-linux-zcx.diff"; charset="UTF-8" Content-Transfer-Encoding: 7bit Content-length: 23582 diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/a-exexpr-gcc.adb gcc-4.6.1/gcc/ada/a-exexpr-gcc.adb --- gcc-4.6.1.orig/gcc/ada/a-exexpr-gcc.adb 2009-04-09 16:00:19.000000000 +0100 +++ gcc-4.6.1/gcc/ada/a-exexpr-gcc.adb 2011-10-07 02:30:41.000000000 +0100 @@ -35,87 +35,11 @@ with Ada.Unchecked_Deallocation; with System.Storage_Elements; use System.Storage_Elements; +with System.Exception_Unwind; use System.Exception_Unwind; separate (Ada.Exceptions) package body Exception_Propagation is - ------------------------------------------------ - -- Entities to interface with the GCC runtime -- - ------------------------------------------------ - - -- These come from "C++ ABI for Itanium: Exception handling", which is - -- the reference for GCC. They are used only when we are relying on - -- back-end tables for exception propagation, which in turn is currently - -- only the case for Zero_Cost_Exceptions in GNAT5. - - -- Return codes from the GCC runtime functions used to propagate - -- an exception. - - type Unwind_Reason_Code is - (URC_NO_REASON, - URC_FOREIGN_EXCEPTION_CAUGHT, - URC_PHASE2_ERROR, - URC_PHASE1_ERROR, - URC_NORMAL_STOP, - URC_END_OF_STACK, - URC_HANDLER_FOUND, - URC_INSTALL_CONTEXT, - URC_CONTINUE_UNWIND); - - pragma Unreferenced - (URC_FOREIGN_EXCEPTION_CAUGHT, - URC_PHASE2_ERROR, - URC_PHASE1_ERROR, - URC_NORMAL_STOP, - URC_END_OF_STACK, - URC_HANDLER_FOUND, - URC_INSTALL_CONTEXT, - URC_CONTINUE_UNWIND); - - pragma Convention (C, Unwind_Reason_Code); - - -- Phase identifiers - - type Unwind_Action is - (UA_SEARCH_PHASE, - UA_CLEANUP_PHASE, - UA_HANDLER_FRAME, - UA_FORCE_UNWIND); - - for Unwind_Action use - (UA_SEARCH_PHASE => 1, - UA_CLEANUP_PHASE => 2, - UA_HANDLER_FRAME => 4, - UA_FORCE_UNWIND => 8); - - pragma Convention (C, Unwind_Action); - - -- Mandatory common header for any exception object handled by the - -- GCC unwinding runtime. - - type Exception_Class is mod 2 ** 64; - - GNAT_Exception_Class : constant Exception_Class := 16#474e552d41646100#; - -- "GNU-Ada\0" - - type Unwind_Word is mod 2 ** System.Word_Size; - for Unwind_Word'Size use System.Word_Size; - -- Map the corresponding C type used in Unwind_Exception below - - type Unwind_Exception is record - Class : Exception_Class := GNAT_Exception_Class; - Cleanup : System.Address := System.Null_Address; - Private1 : Unwind_Word; - Private2 : Unwind_Word; - end record; - -- Map the GCC struct used for exception handling - - for Unwind_Exception'Alignment use Standard'Maximum_Alignment; - -- The C++ ABI mandates the common exception header to be at least - -- doubleword aligned, and the libGCC implementation actually makes it - -- maximally aligned (see unwind.h). See additional comments on the - -- alignment below. - -------------------------------------------------------------- -- GNAT Specific Entities To Deal With The GCC EH Circuitry -- -------------------------------------------------------------- diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/ChangeLog gcc-4.6.1/gcc/ada/ChangeLog --- gcc-4.6.1.orig/gcc/ada/ChangeLog 2011-06-27 11:03:04.000000000 +0100 +++ gcc-4.6.1/gcc/ada/ChangeLog 2011-10-09 11:51:05.000000000 +0100 @@ -1,3 +1,18 @@ +2011-10-09 Luke A. Guest + + * Initial port of ZCX code to ARM Linux. + * s-excunw-gcc.ads: New file, extracts the normal GCC Unwind_Exception + into it's own package. + * s-excunw-gcc-arm.ads: New file, extracts the ARM EABI GCC + Unwind_Exception into it's own package. + * a-exexpr-gcc.adb: Unwind_Exception and other enumerations removed. + * gcc-interface/Makefile.in: Handle new files to build for native and + ARM EABI exception blocks. + * Makefile.rtl: Added a line to build above unwind exception package. + * raise-gcc.c: Added support for ARM EABI UNWINDER. + * system-linux-armeb.ads: Changed to support ZCX instead of SJLJ. + * system-linux-armel.ads: Changed to support ZCX instead of SJLJ. + 2011-06-27 Release Manager * GCC 4.6.1 released. diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/gcc-interface/Makefile.in gcc-4.6.1/gcc/ada/gcc-interface/Makefile.in --- gcc-4.6.1.orig/gcc/ada/gcc-interface/Makefile.in 2011-02-08 22:55:57.000000000 +0000 +++ gcc-4.6.1/gcc/ada/gcc-interface/Makefile.in 2011-10-09 01:05:39.000000000 +0100 @@ -360,6 +360,10 @@ EH_MECHANISM= +# When using the GCC exception handling mechanism, we need to specify which +# Unwind_Exception record to use. +EH_UNWIND_BLOCK= + # Default shared object option. Note that we rely on the fact that the "soname" # option will always be present and last in this flag, so that we can have # $(SO_OPTS)libgnat-x.xx @@ -1869,7 +1873,8 @@ indepsw.adbttype_table - (filter * 4)); + + ttype_entry = _Unwind_decode_target2(ttype_entry); + + return ttype_entry; +} + +#else + static const _Unwind_Ptr get_ttype_entry_for (region_descriptor *region, long filter) { @@ -547,6 +565,8 @@ return ttype_entry; } +#endif /* __ARM_EABI_UNWINDER__ */ + /* Fill out the REGION descriptor for the provided UW_CONTEXT. */ static void @@ -1064,13 +1084,82 @@ typedef _Unwind_Action phases_arg_t; #endif +#ifdef __ARM_EABI_UNWINDER__ + +#define CONTINUE_UNWINDING \ + do \ + { \ + if (__gnu_unwind_frame(uw_exception, uw_context) != _URC_OK) \ + return _URC_FAILURE; \ + return _URC_CONTINUE_UNWIND; \ + } \ + while (0) + +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception* uw_exception, + struct _Unwind_Context* uw_context) +#else _Unwind_Reason_Code PERSONALITY_FUNCTION (version_arg_t version_arg, phases_arg_t phases_arg, _Unwind_Exception_Class uw_exception_class, _Unwind_Exception *uw_exception, _Unwind_Context *uw_context) +#endif { +#ifdef __ARM_EABI_UNWINDER__ + phases_arg_t phases_arg; /* _Unwind_Action actions; */ + _Unwind_Ptr ip; + + _Unwind_Action uw_phases; /*s = (_Unwind_Action) phases_arg;*/ + _GNAT_Exception * gnat_exception = (_GNAT_Exception *) uw_exception; + + region_descriptor region; + action_descriptor action; + + switch (state & _US_ACTION_MASK) + { + case _US_VIRTUAL_UNWIND_FRAME: + phases_arg = _UA_SEARCH_PHASE; + break; + + case _US_UNWIND_FRAME_STARTING: + phases_arg = _UA_CLEANUP_PHASE; + + if (!(state & _US_FORCE_UNWIND) + && uw_exception->barrier_cache.sp == _Unwind_GetGR(uw_context, 13)) + phases_arg |= _UA_HANDLER_FRAME; + break; + + case _US_UNWIND_FRAME_RESUME: + CONTINUE_UNWINDING; + /* return _URC_CONTINUE_UNWIND;*/ + break; + + default: + /* Is this correct? */ + /* return _URC_FATAL_PHASE1_ERROR;*/ + abort (); + } + phases_arg |= state & _US_FORCE_UNWIND; + + uw_phases = phases_arg; + + /* We don't know which runtime we're working with, so can't check this. + * However the ABI routines hide this from us, and we don't actually need + * to know. + */ + /* foreign_exception = false; */ + + /* The dwarf unwinder assumes the context structure holds things like the + * function and LSDA pointers. The ARM implementation caches these in + * the exception header (UCB). To avoid rewriting everything we make the + * virtual IP register point at the UCB. + */ + ip = (_Unwind_Ptr) uw_exception; + + _Unwind_SetGR(uw_context, 12, ip); +#else /* Fetch the version and phases args with their nominal ABI types for later use. This is a noop everywhere except on ia64-vms when called from the Condition Handling Facility. */ @@ -1104,6 +1193,7 @@ return _URC_FATAL_PHASE1_ERROR; } +#endif db_indent (DB_INDENT_RESET); db_phases (uw_phases); diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/s-excunw-gcc.ads gcc-4.6.1/gcc/ada/s-excunw-gcc.ads --- gcc-4.6.1.orig/gcc/ada/s-excunw-gcc.ads 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.6.1/gcc/ada/s-excunw-gcc.ads 2011-10-07 12:40:40.000000000 +0100 @@ -0,0 +1,116 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- S Y S T E M . E X C E P T I O N _ U N W I N D -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This version of the EH data structures is used for normal GCC EH + +package System.Exception_Unwind is + pragma Warnings (Off); + pragma Preelaborate_05; + pragma Warnings (On); + + ------------------------------------------------ + -- Entities to interface with the GCC runtime -- + ------------------------------------------------ + + -- These come from "C++ ABI for Itanium: Exception handling", which is + -- the reference for GCC. They are used only when we are relying on + -- back-end tables for exception propagation, which in turn is currently + -- only the case for Zero_Cost_Exceptions in GNAT5. + + -- Return codes from the GCC runtime functions used to propagate + -- an exception. + + type Unwind_Reason_Code is + (URC_NO_REASON, + URC_FOREIGN_EXCEPTION_CAUGHT, + URC_PHASE2_ERROR, + URC_PHASE1_ERROR, + URC_NORMAL_STOP, + URC_END_OF_STACK, + URC_HANDLER_FOUND, + URC_INSTALL_CONTEXT, + URC_CONTINUE_UNWIND); + + pragma Unreferenced + (URC_FOREIGN_EXCEPTION_CAUGHT, + URC_PHASE2_ERROR, + URC_PHASE1_ERROR, + URC_NORMAL_STOP, + URC_END_OF_STACK, + URC_HANDLER_FOUND, + URC_INSTALL_CONTEXT, + URC_CONTINUE_UNWIND); + + pragma Convention (C, Unwind_Reason_Code); + + -- Phase identifiers + + type Unwind_Action is + (UA_SEARCH_PHASE, + UA_CLEANUP_PHASE, + UA_HANDLER_FRAME, + UA_FORCE_UNWIND); + + for Unwind_Action use + (UA_SEARCH_PHASE => 1, + UA_CLEANUP_PHASE => 2, + UA_HANDLER_FRAME => 4, + UA_FORCE_UNWIND => 8); + + pragma Convention (C, Unwind_Action); + + -- Mandatory common header for any exception object handled by the + -- GCC unwinding runtime. + + type Exception_Class is mod 2 ** 64; + + GNAT_Exception_Class : constant Exception_Class := 16#474e552d41646100#; + -- "GNU-Ada\0" + + type Unwind_Word is mod 2 ** System.Word_Size; + for Unwind_Word'Size use System.Word_Size; + -- Map the corresponding C type used in Unwind_Exception below + + type Unwind_Exception is record + Class : Exception_Class := GNAT_Exception_Class; + Cleanup : System.Address := System.Null_Address; + Private1 : Unwind_Word; + Private2 : Unwind_Word; + end record; + -- Map the GCC struct used for exception handling + + for Unwind_Exception'Alignment use Standard'Maximum_Alignment; + -- The C++ ABI mandates the common exception header to be at least + -- doubleword aligned, and the libGCC implementation actually makes it + -- maximally aligned (see unwind.h). See additional comments on the + -- alignment below. + +end System.Exception_Unwind; diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/s-excunw-gcc-arm.ads gcc-4.6.1/gcc/ada/s-excunw-gcc-arm.ads --- gcc-4.6.1.orig/gcc/ada/s-excunw-gcc-arm.ads 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.6.1/gcc/ada/s-excunw-gcc-arm.ads 2011-10-09 02:00:52.000000000 +0100 @@ -0,0 +1,170 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- S Y S T E M . E X C E P T I O N _ U N W I N D -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This version of the EH data structures is used for ARM EABI GCC EH + +package System.Exception_Unwind is + pragma Warnings (Off); + pragma Preelaborate_05; + pragma Warnings (On); + + ------------------------------------------------ + -- Entities to interface with the GCC runtime -- + ------------------------------------------------ + + -- These come from "C++ ABI for Itanium: Exception handling", which is + -- the reference for GCC. They are used only when we are relying on + -- back-end tables for exception propagation, which in turn is currently + -- only the case for Zero_Cost_Exceptions in GNAT5. + + -- Return codes from the GCC runtime functions used to propagate + -- an exception. + + type Unwind_Reason_Code is + (URC_OK, + URC_FOREIGN_EXCEPTION_CAUGHT, + URC_END_OF_STACK, + URC_HANDLER_FOUND, + URC_INSTALL_CONTEXT, + URC_CONTINUE_UNWIND, + URC_FAILURE); + + pragma Unreferenced + (URC_FOREIGN_EXCEPTION_CAUGHT, + URC_END_OF_STACK, + URC_HANDLER_FOUND, + URC_INSTALL_CONTEXT, + URC_CONTINUE_UNWIND, + URC_FAILURE); + + pragma Convention (C, Unwind_Reason_Code); + + -- Phase identifiers + + type Unwind_State is + (US_VIRTUAL_UNWIND_FRAME, + US_UNWIND_FRAME_STARTING, + US_UNWIND_FRAME_RESUME, + US_ACTION_MASK, + US_FORCE_UNWIND, + US_END_OF_STACK); + + for Unwind_State use + (US_VIRTUAL_UNWIND_FRAME => 0, + US_UNWIND_FRAME_STARTING => 1, + US_UNWIND_FRAME_RESUME => 2, + US_ACTION_MASK => 3, + US_FORCE_UNWIND => 8, + US_END_OF_STACK => 16); + + pragma Convention (C, Unwind_State); + + subtype Unwind_Action is Unwind_State; + + -- UA_SEARCH_PHASE renames Unwind_State.US_UNWIND_FRAME_STARTING; + -- UA_CLEANUP_PHASE renames Unwind_State.US_UNWIND_FRAME_RESUME; + -- UA_HANDLER_FRAME renames Unwind_State.US_; -- 4!?? + -- UA_FORCE_UNWIND renames Unwind_State.US_FORCE_UNWIND; + -- UA_END_OF_STACK renames Unwind_State.US_END_OF_STACK; + + URC_NO_REASON : Unwind_Reason_Code renames URC_OK; + + -- Mandatory common header for any exception object handled by the + -- GCC unwinding runtime. + + type Exception_Class is mod 2 ** 64; + + GNAT_Exception_Class : constant Exception_Class := 16#474e552d41646100#; + -- "GNU-Ada\0" + + type Unwind_Word is mod 2 ** System.Word_Size; + for Unwind_Word'Size use System.Word_Size; + -- Map the corresponding C type used in Unwind_Exception below + + type Unwinder_Caches is record + Reserved1 : Unwind_Word; + Reserved2 : Unwind_Word; + Reserved3 : Unwind_Word; + Reserved4 : Unwind_Word; + end record; + + pragma Convention (C, Unwinder_Caches); + + type Unwind_Array is array (Integer range <>) of Unwind_Word; + + pragma Convention (C, Unwind_Array); + + type Barrier_Caches is record + SP : Unwind_Word; + Bit_Pattern : Unwind_Array (1 .. 5); + end record; + + pragma Convention (C, Barrier_Caches); + + type Unwind_EHT_Header_Ptr is access Unwind_Word; + + pragma Convention (C, Unwind_EHT_Header_Ptr); + + type PR_Caches is record + Function_Start : Unwind_Word; + EHTP : Unwind_EHT_Header_Ptr; + Additional1 : Unwind_Word; + Reserved1 : Unwind_Word; + end record; + + pragma Convention (C, PR_Caches); + + type Unwind_Control_Block is record + Class : Exception_Class := GNAT_Exception_Class; + Cleanup : System.Address := System.Null_Address; + Unwinder_Cache : Unwinder_Caches; + Barrier_Cache : Barrier_Caches; + Cleanup_Cache : Unwind_Array (1 .. 4); + PR_Cache : PR_Caches; + + -- The following are for compatability with the usual GNAT EH mechanism. + Private1 : Unwind_Word; + Private2 : Unwind_Word; + end record; + + pragma Convention (C, Unwind_Control_Block); + -- Map the GCC struct used for exception handling. + -- Found in gcc/config/arm/unwind-arm.h + + for Unwind_Control_Block'Alignment use Standard'Maximum_Alignment; + -- The C++ ABI mandates the common exception header to be at least + -- doubleword aligned, and the libGCC implementation actually makes it + -- maximally aligned (see unwind.h). See additional comments on the + -- alignment below. + + subtype Unwind_Exception is Unwind_Control_Block; + +end System.Exception_Unwind; diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/system-linux-armeb.ads gcc-4.6.1/gcc/ada/system-linux-armeb.ads --- gcc-4.6.1.orig/gcc/ada/system-linux-armeb.ads 2010-01-22 11:55:45.000000000 +0000 +++ gcc-4.6.1/gcc/ada/system-linux-armeb.ads 2011-10-08 22:30:03.000000000 +0100 @@ -147,7 +147,7 @@ Always_Compatible_Rep : constant Boolean := False; Suppress_Standard_Library : constant Boolean := False; Use_Ada_Main_Program_Name : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - GCC_ZCX_Support : constant Boolean := False; + ZCX_By_Default : constant Boolean := True; + GCC_ZCX_Support : constant Boolean := True; end System; diff -x '*~' -uNr gcc-4.6.1.orig/gcc/ada/system-linux-armel.ads gcc-4.6.1/gcc/ada/system-linux-armel.ads --- gcc-4.6.1.orig/gcc/ada/system-linux-armel.ads 2010-01-22 11:55:45.000000000 +0000 +++ gcc-4.6.1/gcc/ada/system-linux-armel.ads 2011-10-08 22:29:43.000000000 +0100 @@ -147,7 +147,7 @@ Always_Compatible_Rep : constant Boolean := False; Suppress_Standard_Library : constant Boolean := False; Use_Ada_Main_Program_Name : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - GCC_ZCX_Support : constant Boolean := False; + ZCX_By_Default : constant Boolean := True; + GCC_ZCX_Support : constant Boolean := True; end System; --=-JleFCquO1Mh6Hrl6A7Mh--