2008-12-24 00:04 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/source/common/expropt1.c
  * harbour/source/common/expropt2.c
    ! fixed wrongly modified expression during optimization for
      ( <numConst> / 0.0 )
    * cleaned bDec/bWidth updating in compile time optimizations

  * harbour/tests/speedtst.prg
    ! fixed possible race condition in initialization
    + added set workarea private for xHarbour builds - thanks to Phil

  * harbour/doc/cmpopt.txt
    * small cleanup

  * harbour/include/hbvmpub.h
  * harbour/source/vm/hvm.c
    % some optimizations mostly for MT mode or compilers which do
      not support function autoinline optimization
This commit is contained in:
Przemyslaw Czerpak
2008-12-23 23:02:06 +00:00
parent 380aa521ab
commit 9e2ee8d66e
7 changed files with 247 additions and 172 deletions

View File

@@ -8,6 +8,25 @@
2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2008-12-24 00:04 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/source/common/expropt1.c
* harbour/source/common/expropt2.c
! fixed wrongly modified expression during optimization for
( <numConst> / 0.0 )
* cleaned bDec/bWidth updating in compile time optimizations
* harbour/tests/speedtst.prg
! fixed possible race condition in initialization
+ added set workarea private for xHarbour builds - thanks to Phil
* harbour/doc/cmpopt.txt
* small cleanup
* harbour/include/hbvmpub.h
* harbour/source/vm/hvm.c
% some optimizations mostly for MT mode or compilers which do
not support function autoinline optimization
2008-12-23 15:45 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbsetup.h
* temporary disabled noreturn function attributes - we have some

View File

@@ -21,7 +21,7 @@ optimized at compile time:
- Harbour extension:
INT( <cConst> )
INT( <nConst> )
ASC( <cConst> [ , ... ] )
MIN( <xConst1>, <xConst2> ) // <xConstN> is N, D or L value
MAX( <xConst1>, <xConst2> ) // <xConstN> is N, D or L value
@@ -128,7 +128,8 @@ arguments are well known and can be callculated at compile time:
<nConst1> ^ <nConst2> => <nConst>
<aValue> [ <nConst> ] => <xArrayItem>
( <expr> ) => <expr> // it allows to optimize expresions like: 1+(2)
( <expr> ) => <expr> // it allows to optimize
// expresions like: 1+(2)
- Harbour extension which may disable RT errors in wrong expressions:
.NOT. .NOT. <expr> => <expr>
@@ -139,9 +140,9 @@ arguments are well known and can be callculated at compile time:
"" + <expr> => <expr>
In cases when result is miningless Harbour compiler can skip code
for operation, f.e. such line of .prg code:
for operation, i.e. for such line of .prg code:
( <exp1> <op> <exp2> )
where result of <op> operation is ignored Harbour reduced the code
where result of <op> operation is ignored Harbour reduces the code
to:
( <exp1>, <exp2> )
@@ -153,7 +154,7 @@ Unlike Clipper Harbour tries to optimize all expressions.
If some code needs strict Clipper behavior then it can be forced by using
-kc Harbour compiler switch. It disabled Harbour extensions and enables
replicating some Clipper bugs like optimizing "" $ <cConst> to .T. at
compile time when it runtime it's .F.
compile time when at runtime it's always .F.
Expressions fully optimized to constant values at compile time can be used
to intialize static variables, f.e.:

View File

@@ -78,8 +78,8 @@ struct _HB_SYMB;
# endif
# define HB_ITEM_GET_NUMINTRAW( p ) ( HB_IS_INTEGER( p ) ? \
( HB_LONG ) p->item.asInteger.value : \
( HB_LONG ) p->item.asLong.value )
( HB_LONG ) (p)->item.asInteger.value : \
( HB_LONG ) (p)->item.asLong.value )
# define HB_ITEM_PUT_NUMINTRAW( p, v ) \
do { \
@@ -97,6 +97,12 @@ struct _HB_SYMB;
} \
} while( 0 )
# define HB_ITEM_GET_NUMDBLRAW( p ) ( HB_IS_INTEGER( p ) ? \
( double ) (p)->item.asInteger.value : \
( HB_IS_LONG( p ) ? \
( double ) (p)->item.asLong.value : \
(p)->item.asDouble.value ) )
#define HB_VM_ISFUNC( pSym ) ( ( pSym )->value.pFunPtr )
#define HB_VM_FUNCUNREF( pSym ) \

View File

@@ -328,6 +328,7 @@ HB_EXPR_PTR hb_compExprNewLong( HB_LONG lValue, HB_COMP_DECL )
pExpr = HB_COMP_EXPR_NEW( HB_ET_NUMERIC );
pExpr->value.asNum.val.l = lValue;
pExpr->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pExpr->value.asNum.bDec = 0;
pExpr->value.asNum.NumType = HB_ET_LONG;
pExpr->ValType = HB_EV_NUMERIC;

View File

@@ -135,6 +135,7 @@ HB_EXPR_PTR hb_compExprReduceMod( HB_EXPR_PTR pSelf, HB_COMP_DECL )
{
pSelf->value.asNum.val.l = pLeft->value.asNum.val.l % pRight->value.asNum.val.l;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.NumType = HB_ET_LONG;
pSelf->ExprType = HB_ET_NUMERIC;
pSelf->ValType = HB_EV_NUMERIC;
@@ -204,10 +205,10 @@ HB_EXPR_PTR hb_compExprReduceDiv( HB_EXPR_PTR pSelf, HB_COMP_DECL )
{
/* Return non-integer results as double */
pSelf->value.asNum.val.d = ( double ) pLeft->value.asNum.val.l / ( double ) pRight->value.asNum.val.l;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = HB_DEFAULT_DECIMALS;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->ExprType = HB_ET_NUMERIC;
}
break;
@@ -233,6 +234,8 @@ HB_EXPR_PTR hb_compExprReduceDiv( HB_EXPR_PTR pSelf, HB_COMP_DECL )
pSelf->value.asNum.val.d = pLeft->value.asNum.val.d / ( double ) pRight->value.asNum.val.l;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = HB_DEFAULT_DECIMALS;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
pSelf->ExprType = HB_ET_NUMERIC;
}
}
else
@@ -242,12 +245,11 @@ HB_EXPR_PTR hb_compExprReduceDiv( HB_EXPR_PTR pSelf, HB_COMP_DECL )
pSelf->value.asNum.val.d = ( double ) pLeft->value.asNum.val.l / pRight->value.asNum.val.d;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = HB_DEFAULT_DECIMALS;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
pSelf->ExprType = HB_ET_NUMERIC;
}
}
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
pSelf->ExprType = HB_ET_NUMERIC;
} /* switch bType */
if( pSelf->ExprType == HB_ET_NUMERIC )
@@ -286,17 +288,15 @@ HB_EXPR_PTR hb_compExprReduceMult( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( HB_DBL_LIM_LONG( dVal ) )
{
pSelf->value.asNum.val.l = pLeft->value.asNum.val.l * pRight->value.asNum.val.l;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_LONG;
}
else
{
pSelf->value.asNum.val.d = ( double ) dVal;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
break;
}
@@ -306,7 +306,6 @@ HB_EXPR_PTR hb_compExprReduceMult( HB_EXPR_PTR pSelf, HB_COMP_DECL )
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = ( UCHAR ) ( pLeft->value.asNum.bDec + pRight->value.asNum.bDec );
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
break;
}
@@ -315,15 +314,14 @@ HB_EXPR_PTR hb_compExprReduceMult( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( pLeft->value.asNum.NumType == HB_ET_DOUBLE )
{
pSelf->value.asNum.val.d = pLeft->value.asNum.val.d * ( double ) pRight->value.asNum.val.l;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pLeft->value.asNum.bDec;
}
else
{
pSelf->value.asNum.val.d = ( double ) pLeft->value.asNum.val.l * pRight->value.asNum.val.d;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pRight->value.asNum.bDec;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
}
@@ -408,16 +406,15 @@ HB_EXPR_PTR hb_compExprReduceMinus( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( HB_DBL_LIM_LONG( dVal ) )
{
pSelf->value.asNum.val.l = pLeft->value.asNum.val.l - pRight->value.asNum.val.l;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_LONG;
}
else
{
pSelf->value.asNum.val.d = ( double ) dVal;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
break;
}
@@ -440,15 +437,14 @@ HB_EXPR_PTR hb_compExprReduceMinus( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( pLeft->value.asNum.NumType == HB_ET_DOUBLE )
{
pSelf->value.asNum.val.d = pLeft->value.asNum.val.d - ( double ) pRight->value.asNum.val.l;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pLeft->value.asNum.bDec;
}
else
{
pSelf->value.asNum.val.d = ( double ) pLeft->value.asNum.val.l - pRight->value.asNum.val.d;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pRight->value.asNum.bDec;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
}
@@ -562,16 +558,15 @@ HB_EXPR_PTR hb_compExprReducePlus( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( HB_DBL_LIM_LONG( dVal ) )
{
pSelf->value.asNum.val.l = pLeft->value.asNum.val.l + pRight->value.asNum.val.l;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_LONG;
}
else
{
pSelf->value.asNum.val.d = ( double ) dVal;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = 0;
break;
}
@@ -589,15 +584,14 @@ HB_EXPR_PTR hb_compExprReducePlus( HB_EXPR_PTR pSelf, HB_COMP_DECL )
if( pLeft->value.asNum.NumType == HB_ET_DOUBLE )
{
pSelf->value.asNum.val.d = pLeft->value.asNum.val.d + ( double ) pRight->value.asNum.val.l;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pLeft->value.asNum.bDec;
}
else
{
pSelf->value.asNum.val.d = ( double ) pLeft->value.asNum.val.l + pRight->value.asNum.val.d;
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.bDec = pRight->value.asNum.bDec;
}
pSelf->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pSelf->value.asNum.NumType = HB_ET_DOUBLE;
}
pSelf->ExprType = HB_ET_NUMERIC;
@@ -742,15 +736,14 @@ HB_EXPR_PTR hb_compExprReduceNegate( HB_EXPR_PTR pSelf, HB_COMP_DECL )
{
pExpr->value.asNum.NumType = HB_ET_DOUBLE;
pExpr->value.asNum.val.d = - ( double ) pExpr->value.asNum.val.l;
pExpr->value.asNum.bWidth = HB_DEFAULT_WIDTH;
pExpr->value.asNum.bDec = 0;
}
else
#endif
{
pExpr->value.asNum.val.l = - pExpr->value.asNum.val.l;
pExpr->value.asNum.bWidth = HB_DEFAULT_WIDTH;
}
pExpr->value.asNum.bWidth = HB_DEFAULT_WIDTH;
}
pSelf->ExprType = HB_ET_NONE; /* suppress deletion of operator components */
HB_COMP_EXPR_FREE( pSelf );

View File

@@ -193,7 +193,6 @@ static void hb_vmSwap( BYTE bCount ); /* swap bCount+1 time two items
/* Pop */
static BOOL hb_vmPopLogical( void ); /* pops the stack latest value and returns its logical value */
static double hb_vmPopNumber( void ); /* pops the stack latest value and returns its numeric value */
static void hb_vmPopAlias( void ); /* pops the workarea number form the eval stack */
static void hb_vmPopAliasedField( PHB_SYMB ); /* pops an aliased field from the eval stack*/
static void hb_vmPopAliasedVar( PHB_SYMB ); /* pops an aliased variable from the eval stack*/
@@ -2003,9 +2002,15 @@ void hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols )
break;
case HB_P_PUSHINT:
HB_TRACE(HB_TR_INFO, ("(HB_P_PUSHINT)"));
hb_vmPushInteger( HB_PCODE_MKSHORT( &pCode[ w + 1 ] ) );
w += 3;
{
PHB_ITEM pItem = hb_stackAllocItem();
pItem->type = HB_IT_INTEGER;
pItem->item.asInteger.value = HB_PCODE_MKSHORT( &pCode[ w + 1 ] );
pItem->item.asInteger.length = 10;
HB_TRACE(HB_TR_INFO, ("(HB_P_PUSHINT)"));
w += 3;
}
break;
case HB_P_PUSHLONG:
@@ -2032,9 +2037,9 @@ void hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols )
case HB_P_PUSHDOUBLE:
hb_vmPushDoubleConst( HB_PCODE_MKDOUBLE( &pCode[ w + 1 ] ),
( int ) * ( BYTE * ) &pCode[ w + 1 + sizeof( double ) ],
( int ) * ( BYTE * ) &pCode[ w + 1 + sizeof( double ) + sizeof( BYTE ) ] );
w += 1 + sizeof( double ) + sizeof( BYTE ) + sizeof( BYTE );
( int ) * ( UCHAR * ) &pCode[ w + 1 + sizeof( double ) ],
( int ) * ( UCHAR * ) &pCode[ w + 2 + sizeof( double ) ] );
w += 3 + sizeof( double );
break;
case HB_P_PUSHSTRSHORT:
@@ -2078,8 +2083,13 @@ void hb_vmExecute( const BYTE * pCode, PHB_SYMB pSymbols )
case HB_P_PUSHDATE:
HB_TRACE( HB_TR_DEBUG, ("(HB_P_PUSHDATE)") );
hb_vmPushDate( ( long ) HB_PCODE_MKLONG( &pCode[ w + 1 ] ) );
w += 5;
{
PHB_ITEM pItem = hb_stackAllocItem();
pItem->type = HB_IT_DATE;
pItem->item.asDate.value = ( long ) HB_PCODE_MKLONG( &pCode[ w + 1 ] );
w += 5;
}
break;
case HB_P_PUSHBLOCK:
@@ -2982,8 +2992,7 @@ static void hb_vmPlus( HB_ITEM_PTR pResult, HB_ITEM_PTR pItem1, HB_ITEM_PTR pIte
double dNumber1 = hb_itemGetNDDec( pItem1, &iDec1 );
double dNumber2 = hb_itemGetNDDec( pItem2, &iDec2 );
hb_itemPutNumType( pResult, dNumber1 + dNumber2, HB_MAX( iDec1, iDec2 ),
HB_ITEM_TYPERAW( pItem1 ), HB_ITEM_TYPERAW( pItem2 ) );
hb_itemPutNDDec( pResult, dNumber1 + dNumber2, HB_MAX( iDec1, iDec2 ) );
}
else if( HB_IS_STRING( pItem1 ) && HB_IS_STRING( pItem2 ) )
{
@@ -3069,8 +3078,7 @@ static void hb_vmMinus( HB_ITEM_PTR pResult, HB_ITEM_PTR pItem1, HB_ITEM_PTR pIt
double dNumber1 = hb_itemGetNDDec( pItem1, &iDec1 );
double dNumber2 = hb_itemGetNDDec( pItem2, &iDec2 );
hb_itemPutNumType( pResult, dNumber1 - dNumber2, HB_MAX( iDec1, iDec2 ),
HB_ITEM_TYPERAW( pItem1 ), HB_ITEM_TYPERAW( pItem2 ) );
hb_itemPutNDDec( pResult, dNumber1 - dNumber2, HB_MAX( iDec1, iDec2 ) );
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
@@ -3482,8 +3490,10 @@ static void hb_vmExactlyEqual( void )
else if( HB_IS_NIL( pItem2 ) )
{
hb_stackDec(); /* pItem2 is already NIL */
hb_stackPop(); /* clear the pItem1 */
hb_vmPushLogical( FALSE );
if( HB_IS_COMPLEX( pItem1 ) )
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = FALSE;
}
else if( HB_IS_STRING( pItem1 ) && HB_IS_STRING( pItem2 ) )
{
@@ -3492,8 +3502,9 @@ static void hb_vmExactlyEqual( void )
pItem2->item.asString.value,
pItem1->item.asString.length ) == 0;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3503,7 +3514,12 @@ static void hb_vmExactlyEqual( void )
hb_stackDec();
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
hb_vmPushLogical( hb_vmPopNumber() == hb_vmPopNumber() );
{
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) ==
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
pItem1->item.asLogical.value = ( pItem1->item.asDate.value ==
@@ -3512,22 +3528,29 @@ static void hb_vmExactlyEqual( void )
hb_stackDec();
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
hb_vmPushLogical( hb_vmPopLogical() == hb_vmPopLogical() );
{
pItem1->item.asLogical.value = pItem1->item.asLogical.value ?
pItem2->item.asLogical.value :
!pItem2->item.asLogical.value;
hb_stackDec();
}
else if( HB_IS_POINTER( pItem1 ) && HB_IS_POINTER( pItem2 ) )
{
BOOL fResult = pItem1->item.asPointer.value == pItem2->item.asPointer.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( HB_IS_HASH( pItem1 ) && HB_IS_HASH( pItem2 ) )
{
BOOL fResult = pItem1->item.asHash.value == pItem2->item.asHash.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( HB_IS_ARRAY( pItem1 ) && HB_IS_ARRAY( pItem2 ) &&
! hb_objHasOperator( pItem1, HB_OO_OP_EXACTEQUAL ) )
@@ -3535,8 +3558,9 @@ static void hb_vmExactlyEqual( void )
BOOL fResult = pItem1->item.asArray.value == pItem2->item.asArray.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( hb_objOperatorCall( HB_OO_OP_EXACTEQUAL, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
@@ -3573,15 +3597,18 @@ static void hb_vmEqual( void )
else if( HB_IS_NIL( pItem2 ) )
{
hb_stackDec(); /* pItem2 is already NIL */
hb_stackPop(); /* clear the pItem1 */
hb_vmPushLogical( FALSE );
if( HB_IS_COMPLEX( pItem1 ) )
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = FALSE;
}
else if( HB_IS_STRING( pItem1 ) && HB_IS_STRING( pItem2 ) )
{
BOOL fResult = hb_itemStrCmp( pItem1, pItem2, FALSE ) == 0;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3591,7 +3618,12 @@ static void hb_vmEqual( void )
hb_stackDec();
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
hb_vmPushLogical( hb_vmPopNumber() == hb_vmPopNumber() );
{
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) ==
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
pItem1->item.asLogical.value = ( pItem1->item.asDate.value ==
@@ -3600,21 +3632,30 @@ static void hb_vmEqual( void )
hb_stackDec();
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
hb_vmPushLogical( hb_vmPopLogical() == hb_vmPopLogical() );
{
pItem1->item.asLogical.value = pItem1->item.asLogical.value ?
pItem2->item.asLogical.value :
!pItem2->item.asLogical.value;
hb_stackDec();
}
else if( HB_IS_POINTER( pItem1 ) && HB_IS_POINTER( pItem2 ) )
{
BOOL fResult = pItem1->item.asPointer.value == pItem2->item.asPointer.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
/*
else if( HB_IS_HASH( pItem1 ) && HB_IS_HASH( pItem2 ) )
{
BOOL fResult = pItem1->item.asHash.value == pItem2->item.asHash.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
*/
else if( hb_objOperatorCall( HB_OO_OP_EQUAL, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
else
@@ -3650,15 +3691,18 @@ static void hb_vmNotEqual( void )
else if( HB_IS_NIL( pItem2 ) )
{
hb_stackDec(); /* pItem2 is already NIL */
hb_stackPop(); /* clear the pItem1 */
hb_vmPushLogical( TRUE );
if( HB_IS_COMPLEX( pItem1 ) )
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = TRUE;
}
else if( HB_IS_STRING( pItem1 ) && HB_IS_STRING( pItem2 ) )
{
int i = hb_itemStrCmp( pItem1, pItem2, FALSE );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( i != 0 );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = i != 0;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3668,7 +3712,12 @@ static void hb_vmNotEqual( void )
hb_stackDec();
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
hb_vmPushLogical( hb_vmPopNumber() != hb_vmPopNumber() );
{
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) !=
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
pItem1->item.asLogical.value = ( pItem1->item.asDate.value !=
@@ -3677,22 +3726,31 @@ static void hb_vmNotEqual( void )
hb_stackDec();
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
hb_vmPushLogical( hb_vmPopLogical() != hb_vmPopLogical() );
{
pItem1->item.asLogical.value = pItem1->item.asLogical.value ?
!pItem2->item.asLogical.value :
pItem2->item.asLogical.value;
hb_stackDec();
}
else if( HB_IS_POINTER( pItem1 ) && HB_IS_POINTER( pItem2 ) )
{
BOOL fValue = pItem1->item.asPointer.value !=
pItem2->item.asPointer.value;
BOOL fResult = pItem1->item.asPointer.value !=
pItem2->item.asPointer.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fValue );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
/*
else if( HB_IS_HASH( pItem1 ) && HB_IS_HASH( pItem2 ) )
{
BOOL fResult = pItem1->item.asHash.value != pItem2->item.asHash.value;
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
*/
else if( hb_objOperatorCall( HB_OO_OP_NOTEQUAL, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
else
@@ -3723,8 +3781,9 @@ static void hb_vmLess( void )
{
int i = hb_itemStrCmp( pItem1, pItem2, FALSE );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( i < 0 );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = i < 0;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3735,9 +3794,10 @@ static void hb_vmLess( void )
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
{
double dNumber2 = hb_vmPopNumber();
double dNumber1 = hb_vmPopNumber();
hb_vmPushLogical( dNumber1 < dNumber2 );
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) <
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
@@ -3748,9 +3808,9 @@ static void hb_vmLess( void )
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
{
BOOL bLogical2 = hb_vmPopLogical();
BOOL bLogical1 = hb_vmPopLogical();
hb_vmPushLogical( bLogical1 < bLogical2 );
pItem1->item.asLogical.value = !pItem1->item.asLogical.value &&
pItem2->item.asLogical.value;
hb_stackDec();
}
else if( hb_objOperatorCall( HB_OO_OP_LESS, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
@@ -3783,8 +3843,9 @@ static void hb_vmLessEqual( void )
{
int i = hb_itemStrCmp( pItem1, pItem2, FALSE );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( i <= 0 );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = i <= 0;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3795,9 +3856,10 @@ static void hb_vmLessEqual( void )
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
{
double dNumber2 = hb_vmPopNumber();
double dNumber1 = hb_vmPopNumber();
hb_vmPushLogical( dNumber1 <= dNumber2 );
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) <=
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
@@ -3808,9 +3870,9 @@ static void hb_vmLessEqual( void )
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
{
BOOL bLogical2 = hb_vmPopLogical();
BOOL bLogical1 = hb_vmPopLogical();
hb_vmPushLogical( bLogical1 <= bLogical2 );
pItem1->item.asLogical.value = !pItem1->item.asLogical.value ||
pItem2->item.asLogical.value;
hb_stackDec();
}
else if( hb_objOperatorCall( HB_OO_OP_LESSEQUAL, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
@@ -3843,8 +3905,9 @@ static void hb_vmGreater( void )
{
int i = hb_itemStrCmp( pItem1, pItem2, FALSE );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( i > 0 );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = i > 0;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3855,9 +3918,10 @@ static void hb_vmGreater( void )
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
{
double dNumber2 = hb_vmPopNumber();
double dNumber1 = hb_vmPopNumber();
hb_vmPushLogical( dNumber1 > dNumber2 );
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) >
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
@@ -3868,9 +3932,9 @@ static void hb_vmGreater( void )
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
{
BOOL bLogical2 = hb_vmPopLogical();
BOOL bLogical1 = hb_vmPopLogical();
hb_vmPushLogical( bLogical1 > bLogical2 );
pItem1->item.asLogical.value = pItem1->item.asLogical.value &&
!pItem2->item.asLogical.value;
hb_stackDec();
}
else if( hb_objOperatorCall( HB_OO_OP_GREATER, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
@@ -3903,8 +3967,9 @@ static void hb_vmGreaterEqual( void )
{
int i = hb_itemStrCmp( pItem1, pItem2, FALSE );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( i >= 0 );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = i >= 0;
}
else if( HB_IS_NUMINT( pItem1 ) && HB_IS_NUMINT( pItem2 ) )
{
@@ -3915,9 +3980,10 @@ static void hb_vmGreaterEqual( void )
}
else if( HB_IS_NUMERIC( pItem1 ) && HB_IS_NUMERIC( pItem2 ) )
{
double dNumber2 = hb_vmPopNumber();
double dNumber1 = hb_vmPopNumber();
hb_vmPushLogical( dNumber1 >= dNumber2 );
pItem1->item.asLogical.value = ( HB_ITEM_GET_NUMDBLRAW( pItem1 ) >=
HB_ITEM_GET_NUMDBLRAW( pItem2 ) );
pItem1->type = HB_IT_LOGICAL;
hb_stackDec();
}
else if( HB_IS_DATE( pItem1 ) && HB_IS_DATE( pItem2 ) )
{
@@ -3928,9 +3994,9 @@ static void hb_vmGreaterEqual( void )
}
else if( HB_IS_LOGICAL( pItem1 ) && HB_IS_LOGICAL( pItem2 ) )
{
BOOL bLogical2 = hb_vmPopLogical();
BOOL bLogical1 = hb_vmPopLogical();
hb_vmPushLogical( bLogical1 >= bLogical2 );
pItem1->item.asLogical.value = pItem1->item.asLogical.value ||
!pItem2->item.asLogical.value;
hb_stackDec();
}
else if( hb_objOperatorCall( HB_OO_OP_GREATEREQUAL, pItem1, pItem1, pItem2, NULL ) )
hb_stackPop();
@@ -3964,8 +4030,9 @@ static void hb_vmInstring( void )
BOOL fResult = ( hb_strAt( pItem1->item.asString.value, pItem1->item.asString.length,
pItem2->item.asString.value, pItem2->item.asString.length ) != 0 );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( HB_IS_HASH( pItem2 ) &&
( HB_IS_HASHKEY( pItem1 ) || hb_hashLen( pItem1 ) == 1 ) )
@@ -3973,8 +4040,9 @@ static void hb_vmInstring( void )
BOOL fResult = hb_hashScan( pItem2, pItem1, NULL );
hb_stackPop();
hb_stackPop();
hb_vmPushLogical( fResult );
hb_itemClear( pItem1 );
pItem1->type = HB_IT_LOGICAL;
pItem1->item.asLogical.value = fResult;
}
else if( hb_objOperatorCall( HB_OO_OP_INCLUDE, pItem1, pItem2, pItem1, NULL ) )
hb_stackPop();
@@ -4003,20 +4071,23 @@ static void hb_vmInstring( void )
static void hb_vmForTest( void ) /* Test to check the end point of the FOR */
{
HB_STACK_TLS_PRELOAD
PHB_ITEM pStep;
BOOL fBack;
HB_TRACE(HB_TR_DEBUG, ("hb_vmForTest()"));
if( HB_IS_NUMERIC( hb_stackItemFromTop( -1 ) ) )
pStep = hb_stackItemFromTop( -1 );
if( HB_IS_NUMERIC( pStep ) )
{
fBack = hb_vmPopNumber() < 0.0;
fBack = HB_ITEM_GET_NUMDBLRAW( pStep ) < 0.0;
hb_stackDec();
}
else
{
PHB_ITEM pResult;
hb_vmPushInteger( 0 );
pResult = hb_errRT_BASE_Subst( EG_ARG, 1073, NULL, "<", 2, hb_stackItemFromTop( -2 ), hb_stackItemFromTop( -1 ) );
pResult = hb_errRT_BASE_Subst( EG_ARG, 1073, NULL, "<", 2, pStep, hb_stackItemFromTop( -1 ) );
if( pResult )
{
@@ -6061,10 +6132,11 @@ void hb_vmPushNil( void )
void hb_vmPushLogical( BOOL bValue )
{
HB_STACK_TLS_PRELOAD
PHB_ITEM pItem = hb_stackAllocItem();
PHB_ITEM pItem;
HB_TRACE(HB_TR_DEBUG, ("hb_vmPushLogical(%d)", (int) bValue));
pItem = hb_stackAllocItem();
pItem->type = HB_IT_LOGICAL;
pItem->item.asLogical.value = bValue;
}
@@ -6709,38 +6781,6 @@ static BOOL hb_vmPopLogical( void )
}
}
/* NOTE: Type checking should be done by the caller. */
static double hb_vmPopNumber( void )
{
HB_STACK_TLS_PRELOAD
PHB_ITEM pItem;
double dNumber;
HB_TRACE(HB_TR_DEBUG, ("hb_vmPopNumber()"));
pItem = hb_stackItemFromTop( -1 );
if( HB_IS_INTEGER( pItem ) )
dNumber = ( double ) pItem->item.asInteger.value;
else if( HB_IS_LONG( pItem ) )
dNumber = ( double ) pItem->item.asLong.value;
else if( HB_IS_DOUBLE( pItem ) )
dNumber = pItem->item.asDouble.value;
else
{
hb_errInternal( HB_EI_VMPOPINVITEM, NULL, "hb_vmPopNumber()", NULL );
dNumber = 0.0; /* To avoid GCC -O2 warning */
}
hb_stackDec();
return dNumber;
}
/* Pops the item from the eval stack and uses it to select the current
* workarea
*/
@@ -9011,8 +9051,8 @@ BOOL hb_xvmEqualInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
double dNumber = hb_vmPopNumber();
hb_vmPushLogical( dNumber == ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) == ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_EQUAL ) )
{
@@ -9059,7 +9099,8 @@ BOOL hb_xvmEqualIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() == ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) == ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_EQUAL ) )
{
@@ -9119,8 +9160,8 @@ BOOL hb_xvmNotEqualInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
double dNumber = hb_vmPopNumber();
hb_vmPushLogical( dNumber != ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) != ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_NOTEQUAL ) )
{
@@ -9167,7 +9208,8 @@ BOOL hb_xvmNotEqualIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() != ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) != ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_NOTEQUAL ) )
{
@@ -9222,7 +9264,8 @@ BOOL hb_xvmLessThenInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
hb_vmPushLogical( hb_vmPopNumber() < ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) < ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_LESS ) )
{
@@ -9264,7 +9307,8 @@ BOOL hb_xvmLessThenIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() < ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) < ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_LESS ) )
{
@@ -9319,7 +9363,8 @@ BOOL hb_xvmLessEqualThenInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
hb_vmPushLogical( hb_vmPopNumber() <= ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) <= ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_LESSEQUAL ) )
{
@@ -9361,7 +9406,8 @@ BOOL hb_xvmLessEqualThenIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() <= ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) <= ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_LESSEQUAL ) )
{
@@ -9416,7 +9462,8 @@ BOOL hb_xvmGreaterThenInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
hb_vmPushLogical( hb_vmPopNumber() > ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) > ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_GREATER ) )
{
@@ -9458,7 +9505,8 @@ BOOL hb_xvmGreaterThenIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() > ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) > ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_GREATER ) )
{
@@ -9513,7 +9561,8 @@ BOOL hb_xvmGreaterEqualThenInt( LONG lValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
hb_vmPushLogical( hb_vmPopNumber() >= ( double ) lValue );
pItem->item.asLogical.value = HB_ITEM_GET_NUMDBLRAW( pItem ) >= ( double ) lValue;
pItem->type = HB_IT_LOGICAL;
}
else if( hb_objHasOperator( pItem, HB_OO_OP_GREATEREQUAL ) )
{
@@ -9555,7 +9604,8 @@ BOOL hb_xvmGreaterEqualThenIntIs( LONG lValue, BOOL * pfValue )
}
else if( HB_IS_NUMERIC( pItem ) )
{
* pfValue = hb_vmPopNumber() >= ( double ) lValue;
* pfValue = HB_ITEM_GET_NUMDBLRAW( pItem ) >= ( double ) lValue;
hb_stackDec();
}
else if( hb_objHasOperator( pItem, HB_OO_OP_GREATEREQUAL ) )
{

View File

@@ -11,7 +11,6 @@
*
*/
#define N_TESTS 54
#define N_LOOPS 1000000
#define ARR_LEN 16
@@ -241,7 +240,13 @@ return
/* initialize mutex in hb_trheadDoOnce() */
init proc once_init()
set workarea private
hb_threadOnce()
/* initialize error object to reduce possible crashes when two
* threads will try to create new error class simultaneously
* xHarbour does not have any protection against such situation
*/
errorNew()
return
function hb_threadOnce( xOnceControl, bAction )
@@ -253,11 +258,11 @@ function hb_threadOnce( xOnceControl, bAction )
if xOnceControl == NIL
hb_mutexLock( s_mutex )
if xOnceControl == NIL
xOnceControl := .t.
lFirstCall := .t.
if bAction != NIL
eval( bAction )
endif
xOnceControl := .t.
lFirstCall := .t.
endif
hb_mutexUnlock( s_mutex )
endif
@@ -275,15 +280,15 @@ TEST t002 WITH L_N:=112345.67 CODE x := L_N
TEST t003 WITH L_D:=date() CODE x := L_D
TEST t004 INIT _( static s_once, S_C ) ;
INIT iif( hb_threadOnce( @s_once ), S_C := dtos(date()), ) ;
INIT hb_threadOnce( @s_once, {|| S_C := dtos( date() ) } ) ;
CODE x := S_C
TEST t005 INIT _( static s_once, S_N ) ;
INIT iif( hb_threadOnce( @s_once ), S_N := 112345.67, ) ;
INIT hb_threadOnce( @s_once, {|| S_N := 112345.67 } ) ;
CODE x := S_N
TEST t006 INIT _( static s_once, S_D ) ;
INIT iif( hb_threadOnce( @s_once ), S_D := date(), ) ;
INIT hb_threadOnce( @s_once, {|| S_D := date() } ) ;
CODE x := S_D
TEST t007 INIT _( memvar M_C ) INIT _( private M_C := dtos( date() ) ) ;
@@ -298,19 +303,19 @@ TEST t009 INIT _( memvar M_D ) INIT _( private M_D := date() ) ;
TEST t010 INIT _( memvar P_C ) ;
INIT _( static s_once ) ;
INIT _( public P_C ) ;
INIT iif( hb_threadOnce( @s_once ), P_C := dtos( date() ), ) ;
INIT hb_threadOnce( @s_once, {|| P_C := dtos( date() ) } ) ;
CODE x := P_C
TEST t011 INIT _( memvar P_N ) ;
INIT _( static s_once ) ;
INIT _( public P_N ) ;
INIT iif( hb_threadOnce( @s_once ), P_N := 112345.67, ) ;
INIT hb_threadOnce( @s_once, {|| P_N := 112345.67 } ) ;
CODE x := P_N
TEST t012 INIT _( memvar P_D ) ;
INIT _( static s_once ) ;
INIT _( public P_D ) ;
INIT iif( hb_threadOnce( @s_once ), P_D := date(), ) ;
INIT hb_threadOnce( @s_once, {|| P_D := date() } ) ;
CODE x := P_D
TEST t013 INIT _( field F_C ) INIT use_dbsh() EXIT close_db() ;