/* * Detach local variable (swap current value with a memvar handle) */ PHB_ITEM hb_memvarDetachLocal( PHB_ITEM pLocal ) { HB_TRACE( HB_TR_DEBUG, ( "hb_memvarDetachLocal(%p)", pLocal ) ); if( HB_IS_BYREF( pLocal ) ) { do { if( HB_IS_MEMVAR( pLocal ) || HB_IS_EXTREF( pLocal ) ) break; else if( HB_IS_ENUM( pLocal ) ) { if( ! pLocal->item.asEnum.valuePtr ) { PHB_ITEM pBase = HB_IS_BYREF( pLocal->item.asEnum.basePtr ) ? hb_itemUnRef( pLocal->item.asEnum.basePtr ) : pLocal->item.asEnum.basePtr; if( HB_IS_ARRAY( pBase ) ) { PHB_ITEM pItem = hb_itemNew( NULL ); hb_arrayGetItemRef( pBase, pLocal->item.asEnum.offset, pItem ); pLocal->item.asEnum.valuePtr = pItem; pLocal = pItem; break; } } } else if( pLocal->item.asRefer.value >= 0 && pLocal->item.asRefer.offset == 0 ) break; pLocal = hb_itemUnRefOnce( pLocal ); } while( HB_IS_BYREF( pLocal ) ); } /* Change the value only if this variable is not referenced * by another codeblock yet. * In this case we have to copy the current value to a global memory * pool so it can be shared by codeblocks */ if( ! HB_IS_MEMVAR( pLocal ) ) { PHB_ITEM pMemvar = hb_memvarValueNew(); hb_itemRawCpy( pMemvar, pLocal ); pMemvar->type &= ~HB_IT_DEFAULT; pLocal->type = HB_IT_BYREF | HB_IT_MEMVAR; pLocal->item.asMemvar.value = pMemvar; } return pLocal; }
/* Mark a passed item as used so it will be not released by the GC */ void hb_gcItemRef( PHB_ITEM pItem ) { while( HB_IS_BYREF( pItem ) ) { if( HB_IS_ENUM( pItem ) ) return; else if( HB_IS_EXTREF( pItem ) ) { pItem->item.asExtRef.func->mark( pItem->item.asExtRef.value ); return; } else if( ! HB_IS_MEMVAR( pItem ) && pItem->item.asRefer.offset == 0 && pItem->item.asRefer.value >= 0 ) { /* array item reference */ PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asRefer.BasePtr.array ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all array elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } return; } pItem = hb_itemUnRefOnce( pItem ); } if( HB_IS_ARRAY( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asArray.value ); /* Check this array only if it was not checked yet */ if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this array as used so it will be no re-checked from * other references */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all array elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_HASH( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asHash.value ); /* Check this hash table only if it was not checked yet */ if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this hash table as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all hash elements */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_BLOCK( pItem ) ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asBlock.value ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this codeblock as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark as used all detached variables in a codeblock */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } else if( HB_IS_POINTER( pItem ) ) { if( pItem->item.asPointer.collect ) { PHB_GARBAGE pAlloc = HB_GC_PTR( pItem->item.asPointer.value ); if( ( pAlloc->used & ~HB_GC_DELETE ) == s_uUsedFlag ) { /* mark this memory block as used */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all internal user blocks attached to this block */ pAlloc->pFuncs->mark( HB_BLOCK_PTR( pAlloc ) ); } } } /* all other data types don't need the GC */ }
/* Mark a passed item as used so it will be not released by the GC */ void hb_gcItemRef( HB_ITEM_PTR pItem ) { HB_THREAD_STUB ULONG ulSize; HB_ITEM FakedItem; PHB_ITEM pKey; PHB_ITEM pValue; HB_CODEBLOCK_PTR pCBlock; USHORT ui; #ifdef SIMULATE_ITEMREF_RECURSION PITEMREF_RESUMEINFO pResumeInfo = (PITEMREF_RESUMEINFO) hb_xgrab( sizeof( ITEMREF_RESUMEINFO ) ); int iResumeCounter = 0; #endif FakedItem.type = HB_IT_ARRAY; ItemRef_Top: while( HB_IS_BYREF( pItem ) ) { if( HB_IS_EXTREF( pItem ) ) { pItem->item.asExtRef.func->mark( pItem->item.asExtRef.value ); RETURN_OR_RESUME_ITEMREF(); } if( HB_IS_MEMVAR( pItem ) == FALSE ) { if( pItem->item.asRefer.offset == 0 ) { FakedItem.item.asArray.value = pItem->item.asRefer.BasePtr.pBaseArray; //hb_gcItemRef( &FakedItem ); NESTED_ITEMREF( &FakedItem, 1 ); ItemRef_ResumePoint_1: // return; RETURN_OR_RESUME_ITEMREF(); } } else { if( HB_VM_STACK.pPos == HB_VM_STACK.pItems ) { //return; RETURN_OR_RESUME_ITEMREF(); } } pItem = hb_itemUnRefOnce( pItem ); } if( HB_IS_ARRAY( pItem ) ) { HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pItem->item.asArray.value; //printf( "Array %p\n", pItem->item.asArray.value ); --pAlloc; /* Check this array only if it was not checked yet */ if( pAlloc->used == s_uUsedFlag ) { ulSize = pItem->item.asArray.value->ulLen; /* mark this block as used so it will be no re-checked from * other references */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all array elements */ pItem = pItem->item.asArray.value->pItems; //printf( "Items %p\n", pItem ); while( ulSize ) { //printf( "Item %p\n", pItem ); //hb_gcItemRef( pItem ); NESTED_ITEMREF( pItem, 2 ); ItemRef_ResumePoint_2: ++pItem; --ulSize; } } } else if( HB_IS_HASH( pItem ) ) { HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pItem->item.asHash.value; --pAlloc; /* Check this hash only if it was not checked yet */ if( pAlloc->used == s_uUsedFlag ) { ulSize = pItem->item.asHash.value->ulLen; pKey = pItem->item.asHash.value->pKeys; pValue = pItem->item.asHash.value->pValues; /* mark this block as used so it will be no re-checked from * other references */ pAlloc->used ^= HB_GC_USED_FLAG; /* mark also all hash elements */ while( ulSize ) { //printf( "Kry %p Value: %p\n", pKey, pValue ); //hb_gcItemRef( pKey ); NESTED_ITEMREF( pKey, 3 ); ItemRef_ResumePoint_3: //hb_gcItemRef( pValue ); NESTED_ITEMREF( pValue, 4 ); ItemRef_ResumePoint_4: ++pKey; ++pValue; --ulSize; } } } else if( HB_IS_BLOCK( pItem ) ) { HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pItem->item.asBlock.value; --pAlloc; /* Check this block only if it was not checked yet */ if( pAlloc->used == s_uUsedFlag ) { pCBlock = pItem->item.asBlock.value; ui = 1; pAlloc->used ^= HB_GC_USED_FLAG; /* mark this codeblock as used */ /* mark as used all detached variables in a codeblock */ while( ui <= pCBlock->uiLocals ) { //hb_gcItemRef( &pCBlock->pLocals[ ui ] ); NESTED_ITEMREF( &pCBlock->pLocals[ ui ] , 5 ); ItemRef_ResumePoint_5: ++ui; } } } else if( HB_IS_POINTER( pItem ) ) { /* check if this memory was allocated by a hb_gcAlloc() */ if ( pItem->item.asPointer.collect ) { HB_GARBAGE_PTR pAlloc = ( HB_GARBAGE_PTR ) pItem->item.asPointer.value; --pAlloc; /* Check this memory only if it was not checked yet */ if( pAlloc->used == s_uUsedFlag ) { /* mark this memory as used so it will be no re-checked from * other references */ pAlloc->used ^= HB_GC_USED_FLAG; } } } /* all other data types don't need the GC */ RETURN_OR_RESUME_ITEMREF(); }