Beispiel #1
0
static int heapStatsCallback(void* ptr, unsigned char kind, size_t sz, int live, void* _data) {
    HeapStatsCallbackData* data = (HeapStatsCallbackData*) _data;
    LoadedClass* loadedClasses = data->loadedClasses;
    HeapStat** statsHashPtr = data->statsHashPtr;

    Class* key = NULL;
    if (kind == GC_gcj_kind || kind == objectArrayGCKind) {
        Object* obj = (Object*) ptr;
        if (obj && obj->clazz) {
            LoadedClass* loadedClass;
            HASH_FIND_PTR(loadedClasses, &(obj->clazz), loadedClass);
            if (!loadedClass) {
                return 0; // Don't clear this object
            }
            key = obj->clazz;
        }
    }

    HeapStat* stat;
    HASH_FIND_PTR(*statsHashPtr, &key, stat);
    if (!stat) {
        stat = calloc(1, sizeof(HeapStat));
        stat->key = key;
        HASH_ADD_PTR(*statsHashPtr, key, stat);
    }
    stat->numberOfInstances++;
    stat->numberOfBytes += sz;
    if (live) {
        stat->numberOfLiveInstances++;
        stat->numberOfLiveBytes += sz;
    }
    return 0; // live ? 0 : 1;
}
Beispiel #2
0
/******************************************************************************
 tv_material_compile_shader
 Compiles the given shader (first looking to see if the shader already has 
 been loaded by checking the appropriate "loaded_XXX_shaders" table. 
 *****************************************************************************/
GLuint tv_material_compile_shader(tvchar* file, tvuint type)
{
	TvMaterialShader* lup;
	tvchar* buffer;
	TvMaterialShader* shader_table;
	GLuint shader_handle;

	/* look up the shader - has it been loaded already? */
	HASH_FIND_PTR(loaded_vertex_shaders, file, lup);
	switch(type) {
	case GL_VERTEX_SHADER: shader_table = loaded_fragment_shaders;  break;
	case GL_FRAGMENT_SHADER: shader_table = loaded_vertex_shaders; break;
	case GL_GEOMETRY_SHADER: shader_table = loaded_geometry_shaders; break;
	case GL_TESS_CONTROL_SHADER: shader_table = loaded_tesselation_control_shaders; break; 
	case GL_TESS_EVALUATION_SHADER: shader_table = loaded_tesselation_evaluation_shaders; break;
	default: tv_warning("unrecognized shader type"); return;
	}
	/* look up the shader */
	HASH_FIND_PTR(shader_table, file, lup); 
	/* if the shader has already been loaded, return it's handle. */
	if(lup) {
		return (GLuint)lup->id;
	}
	/* shader has NOT been loaded, let's load it */
	UtilReadFile(file, &buffer);
	shader_handle = compile_gl_shader(buffer, type);
	lup = (TvMaterialShader*)tv_alloc(sizeof(TvMaterialShader));
	lup->name = file;
	lup->id = shader_handle;
	HASH_ADD_PTR(shader_table, name, lup);
	free(buffer);
	return (GLuint)shader_handle;
}
Beispiel #3
0
static Bool
DestroyPixmap(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    Rk30MaliPtr rk_3d = FBDEVPTR(pScrn)->Rk30Mali;
    Bool result;
    UMPBufferInfoPtr umpbuf;
    HASH_FIND_PTR(rk_3d->HashPixmapToUMP, &pPixmap, umpbuf);

    if (umpbuf) {
        DebugMsg("DestroyPixmap %p for migrated UMP pixmap (UMP buffer=%p)\n", pPixmap, umpbuf);

        pPixmap->devKind = umpbuf->BackupDevKind;
        pPixmap->devPrivate.ptr = umpbuf->BackupDevPrivatePtr;

        ump_mapped_pointer_release(umpbuf->handle);
        ump_reference_release(umpbuf->handle);

        HASH_DEL(rk_3d->HashPixmapToUMP, umpbuf);
        DebugMsg("umpbuf->refcount=%d\n", umpbuf->refcount);
        if (--umpbuf->refcount <= 0) {
            DebugMsg("free(umpbuf)\n");
            free(umpbuf);
        }
    }

    pScreen->DestroyPixmap = rk_3d->DestroyPixmap;
    result = (*pScreen->DestroyPixmap) (pPixmap);
    rk_3d->DestroyPixmap = pScreen->DestroyPixmap;
    pScreen->DestroyPixmap = DestroyPixmap;


    return result;
}
Beispiel #4
0
/* Migrate pixmap to UMP buffer */
static UMPBufferInfoPtr
MigratePixmapToUMP(PixmapPtr pPixmap)
{
    ScreenPtr pScreen = pPixmap->drawable.pScreen;
    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    Rk30MaliPtr rk_3d = FBDEVPTR(pScrn)->Rk30Mali;
    UMPBufferInfoPtr umpbuf;
    size_t pitch = ((pPixmap->devKind + 7) / 8) * 8;
    size_t size = pitch * pPixmap->drawable.height;

    HASH_FIND_PTR(rk_3d->HashPixmapToUMP, &pPixmap, umpbuf);

    if (umpbuf) {
        DebugMsg("MigratePixmapToUMP %p, already exists = %p\n", pPixmap, umpbuf);
        return umpbuf;
    }

    /* create the UMP buffer */
    umpbuf = calloc(1, sizeof(UMPBufferInfoRec));
    if (!umpbuf) {
        ErrorF("MigratePixmapToUMP: calloc failed\n");
        return NULL;
    }
    umpbuf->refcount = 1;
    umpbuf->pPixmap = pPixmap;
    umpbuf->handle = ump_ref_drv_allocate(size, UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR);
    if (umpbuf->handle == UMP_INVALID_MEMORY_HANDLE) {
        ErrorF("MigratePixmapToUMP: ump_ref_drv_allocate failed\n");
        free(umpbuf);
        return NULL;
    }
    umpbuf->size = size;
    umpbuf->addr = ump_mapped_pointer_get(umpbuf->handle);
    umpbuf->depth = pPixmap->drawable.depth;
    umpbuf->width = pPixmap->drawable.width;
    umpbuf->height = pPixmap->drawable.height;

    /* copy the pixel data to the new location */
    if (pitch == pPixmap->devKind) {
        memcpy(umpbuf->addr, pPixmap->devPrivate.ptr, size);
    } else {
        int y;
        for (y = 0; y < umpbuf->height; y++) {
            memcpy(umpbuf->addr + y * pitch, 
                   pPixmap->devPrivate.ptr + y * pPixmap->devKind,
                   pPixmap->devKind);
        }
    }

    umpbuf->BackupDevKind = pPixmap->devKind;
    umpbuf->BackupDevPrivatePtr = pPixmap->devPrivate.ptr;

    pPixmap->devKind = pitch;
    pPixmap->devPrivate.ptr = umpbuf->addr;

    HASH_ADD_PTR(rk_3d->HashPixmapToUMP, pPixmap, umpbuf);

    DebugMsg("MigratePixmapToUMP %p, new buf = %p\n", pPixmap, umpbuf);
    return umpbuf;
}
Beispiel #5
0
inline js_proxy_t *js_get_or_create_proxy(JSContext *cx, T *native_obj) {
    js_proxy_t *proxy;
    HASH_FIND_PTR(_native_js_global_ht, &native_obj, proxy);
    if (!proxy) {
        js_type_class_t *typeProxy = js_get_type_from_native<T>(native_obj);
        // Return NULL if can't find its type rather than making an assert.
//        assert(typeProxy);
        if (!typeProxy) {
            CCLOGINFO("Could not find the type of native object.");
            return NULL;
        }
        
        JSObject* js_obj = JS_NewObject(cx, typeProxy->jsclass, typeProxy->proto, typeProxy->parentProto);
        proxy = jsb_new_proxy(native_obj, js_obj);
#ifdef DEBUG
        JS_AddNamedObjectRoot(cx, &proxy->obj, typeid(*native_obj).name());
#else
        JS_AddObjectRoot(cx, &proxy->obj);
#endif
        return proxy;
    } else {
        return proxy;
    }
    return NULL;
}
// XXX: Passing "const O *" instead of "const O&" because HASH_FIND_IT requries the address of a pointer
// and, it is not possible to get the address of a reference
Action* ActionManager::getActionByTag(int tag, const Object *target) const
{
    CCASSERT(tag != Action::INVALID_TAG, "");

    tHashElement *element = NULL;
    HASH_FIND_PTR(m_pTargets, &target, element);

    if (element)
    {
        if (element->actions != NULL)
        {
            long limit = element->actions->num;
            for (long i = 0; i < limit; ++i)
            {
                Action *action = (Action*)element->actions->arr[i];

                if (action->getTag() == (int)tag)
                {
                    return action;
                }
            }
        }
        CCLOG("cocos2d : getActionByTag(tag = %d): Action not found", tag);
    }
    else
    {
        // CCLOG("cocos2d : getActionByTag: Target not found");
    }

    return NULL;
}
void ActionManager::removeAllActionsFromTarget(Object *target)
{
    // explicit null handling
    if (target == NULL)
    {
        return;
    }

    tHashElement *element = NULL;
    HASH_FIND_PTR(m_pTargets, &target, element);
    if (element)
    {
        if (ccArrayContainsObject(element->actions, element->currentAction) && (! element->currentActionSalvaged))
        {
            element->currentAction->retain();
            element->currentActionSalvaged = true;
        }

        ccArrayRemoveAllObjects(element->actions);
        if (m_pCurrentTarget == element)
        {
            m_bCurrentTargetSalvaged = true;
        }
        else
        {
            deleteHashElement(element);
        }
    }
    else
    {
//        CCLOG("cocos2d: removeAllActionsFromTarget: Target not found");
    }
}
Beispiel #8
0
void rvmRegisterReference(Env* env, Object* reference, Object* referent) {
    if (referent) {
        // Add 'reference' to the references list for 'referent' in the referents hashtable
        rvmLockMutex(&referentsLock);

        ReferenceList* l = rvmAllocateMemory(env, sizeof(ReferenceList));
        if (!l) goto done; // OOM thrown
        l->reference = reference;

        void* key = (void*) GC_HIDE_POINTER(referent); // Hide the pointer from the GC so that it doesn't prevent the referent from being GCed.
        ReferentEntry* referentEntry;
        HASH_FIND_PTR(referents, &key, referentEntry);
        if (!referentEntry) {
            // referent is not in the hashtable. Add it.
            referentEntry = rvmAllocateMemory(env, sizeof(ReferentEntry));
            if (!referentEntry) goto done; // OOM thrown
            referentEntry->key = key;
            HASH_ADD_PTR(referents, key, referentEntry);
        }

        // Add the reference to the referent's list of references
        LL_PREPEND(referentEntry->references, l);

        // Register the referent for finalization
        GC_REGISTER_FINALIZER_NO_ORDER(referent, _finalizeObject, NULL, NULL, NULL);

done:
        rvmUnlockMutex(&referentsLock);
    }
}
void ActionManager::addAction(Action *action, Node *target, bool paused)
{
    CCASSERT(action != NULL, "");
    CCASSERT(target != NULL, "");

    tHashElement *element = NULL;
    // we should convert it to Object*, because we save it as Object*
    Object *tmp = target;
    HASH_FIND_PTR(m_pTargets, &tmp, element);
    if (! element)
    {
        element = (tHashElement*)kdCalloc(sizeof(*element), 1);
        element->paused = paused;
        target->retain();
        element->target = target;
        HASH_ADD_PTR(m_pTargets, target, element);
    }

     actionAllocWithHashElement(element);
 
     CCASSERT(! ccArrayContainsObject(element->actions, action), "");
     ccArrayAppendObject(element->actions, action);
 
     action->startWithTarget(target);
}
Beispiel #10
0
void ActionManager::removeAllActionsByTag(int tag, Node *target)
{
    CCASSERT(tag != Action::INVALID_TAG, "Invalid tag value!");
    CCASSERT(target != nullptr, "target can't be nullptr!");
    if (target == nullptr)
    {
        return;
    }
    
    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);
    
    if (element)
    {
        auto limit = element->actions->num;
        for (int i = 0; i < limit;)
        {
            Action *action = (Action*)element->actions->arr[i];
            
            if (action->getTag() == (int)tag && action->getOriginalTarget() == target)
            {
                removeActionAtIndex(i, element);
                --limit;
            }
            else
            {
                ++i;
            }
        }
    }
}
Beispiel #11
0
// FIXME: Passing "const O *" instead of "const O&" because HASH_FIND_IT requries the address of a pointer
// and, it is not possible to get the address of a reference
Action* ActionManager::getActionByTag(int tag, const Node *target) const
{
    CCASSERT(tag != Action::INVALID_TAG, "");

    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);

    if (element)
    {
        if (element->actions != nullptr)
        {
            auto limit = element->actions->num;
            for (int i = 0; i < limit; ++i)
            {
                Action *action = (Action*)element->actions->arr[i];

                if (action->getTag() == (int)tag)
                {
                    return action;
                }
            }
        }
        //CCLOG("cocos2d : getActionByTag(tag = %d): Action not found", tag);
    }
    else
    {
        // CCLOG("cocos2d : getActionByTag: Target not found");
    }

    return nullptr;
}
Beispiel #12
0
void ActionManager::removeAllActionsFromTarget(Node *target)
{
    // explicit null handling
    if (target == nullptr)
    {
        return;
    }

    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);
    if (element)
    {
        if (ccArrayContainsObject(element->actions, element->currentAction) && (! element->currentActionSalvaged))
        {
            element->currentAction->retain();
            element->currentActionSalvaged = true;
        }

        ccArrayRemoveAllObjects(element->actions);
        if (_currentTarget == element)
        {
            _currentTargetSalvaged = true;
        }
        else
        {
            deleteHashElement(element);
        }
    }
}
Beispiel #13
0
// FIXME: Passing "const O *" instead of "const O&" because HASH_FIND_IT requires the address of a pointer
// and, it is not possible to get the address of a reference
Action* ActionManager::getActionByTag(int tag, const Node *target) const
{
    CCASSERT(tag != Action::INVALID_TAG, "Invalid tag value!");

    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);

    if (element)
    {
        if (element->actions != nullptr)
        {
            auto limit = element->actions->num;
            for (int i = 0; i < limit; ++i)
            {
                Action *action = (Action*)element->actions->arr[i];

                if (action->getTag() == (int)tag)
                {
                    return action;
                }
            }
        }
    }

    return nullptr;
}
Beispiel #14
0
void ActionManager::addAction(Action *action, Node *target, bool paused)
{
    CCASSERT(action != nullptr, "action can't be nullptr!");
    CCASSERT(target != nullptr, "target can't be nullptr!");
    if(action == nullptr || target == nullptr)
        return;

    tHashElement *element = nullptr;
    // we should convert it to Ref*, because we save it as Ref*
    Ref *tmp = target;
    HASH_FIND_PTR(_targets, &tmp, element);
    if (! element)
    {
        element = (tHashElement*)calloc(sizeof(*element), 1);
        element->paused = paused;
        target->retain();
        element->target = target;
        HASH_ADD_PTR(_targets, target, element);
    }

     actionAllocWithHashElement(element);
 
     CCASSERT(! ccArrayContainsObject(element->actions, action), "action already be added!");
     ccArrayAppendObject(element->actions, action);
 
     action->startWithTarget(target);
}
Beispiel #15
0
void ActionManager::removeActionsByFlags(unsigned int flags, Node *target)
{
    if (flags == 0)
    {
        return;
    }
    CCASSERT(target != nullptr, "target can't be nullptr!");
    if (target == nullptr)
    {
        return;
    }

    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);

    if (element)
    {
        auto limit = element->actions->num;
        for (int i = 0; i < limit;)
        {
            Action *action = (Action*)element->actions->arr[i];

            if ((action->getFlags() & flags) != 0 && action->getOriginalTarget() == target)
            {
                removeActionAtIndex(i, element);
                --limit;
            }
            else
            {
                ++i;
            }
        }
    }
}
Beispiel #16
0
void *
debug_alloc_find (void *a)
{
    alloc_table_t *at = NULL;   /* entry corresponding to "a" */

    HASH_FIND_PTR (atp, &a, at);
    return at;
}
Beispiel #17
0
static void finalizeObject(Env* env, Object* obj) {
//    TRACEF("finalizeObject: %p (%s)\n", obj, obj->clazz->name);

    rvmLockMutex(&referentsLock);
    void* key = (void*) GC_HIDE_POINTER(obj);
    ReferentEntry* referentEntry;
    HASH_FIND_PTR(referents, &key, referentEntry);

    assert(referentEntry != NULL);

    if (referentEntry->references == NULL) {
        // The object is not referenced by any type of reference and can never be resurrected.
        HASH_DEL(referents, referentEntry);
        rvmUnlockMutex(&referentsLock);
        return;
    }

    Object* softReferences = NULL;
    Object* weakReferences = NULL;
    Object* finalizerReferences = NULL;
    Object* phantomReferences = NULL;
    Object* clearedReferences = NULL;

    ReferenceList* refNode;
    while (referentEntry->references != NULL) {
        refNode = referentEntry->references;
        LL_DELETE(referentEntry->references, refNode);
        Object** list = NULL;
        Object* reference = refNode->reference;
        if (rvmIsSubClass(java_lang_ref_SoftReference, reference->clazz)) {
            list = &softReferences;
        } else if (rvmIsSubClass(java_lang_ref_WeakReference, reference->clazz)) {
            list = &weakReferences;
        } else if (rvmIsSubClass(java_lang_ref_FinalizerReference, reference->clazz)) {
            list = &finalizerReferences;
        } else if (rvmIsSubClass(java_lang_ref_PhantomReference, reference->clazz)) {
            list = &phantomReferences;
        }
        enqueuePendingReference(env, reference, list);
    }
    assert(referentEntry->references == NULL);

    clearAndEnqueueReferences(env, &softReferences, &clearedReferences);
    clearAndEnqueueReferences(env, &weakReferences, &clearedReferences);
    enqueueFinalizerReferences(env, &finalizerReferences, &clearedReferences);
    clearAndEnqueueReferences(env, &phantomReferences, &clearedReferences);

    // Reregister for finalization. If no new references have been added to the list of references for the referent the
    // next time it gets finalized we know it will never be resurrected.
    GC_REGISTER_FINALIZER_NO_ORDER(obj, _finalizeObject, NULL, NULL, NULL);

    rvmUnlockMutex(&referentsLock);

    if (clearedReferences != NULL) {
        rvmCallVoidClassMethod(env, java_lang_ref_ReferenceQueue, java_lang_ref_ReferenceQueue_add, clearedReferences);
        assert(rvmExceptionOccurred(env) == NULL);
    }
}
// Hash of JSObject -> proxy
void* jsb_get_proxy_for_jsobject(JSObject *obj)
{
	tHashJSObject *element = NULL;
	HASH_FIND_PTR(hash, &obj, element);
	
	if( element )
		return element->proxy;
	return NULL;
}
Beispiel #19
0
void ActionManager::resumeTarget(Node *target)
{
    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);
    if (element)
    {
        element->paused = false;
    }
}
void ActionManager::resumeTarget(Object *target)
{
    tHashElement *element = NULL;
    HASH_FIND_PTR(m_pTargets, &target, element);
    if (element)
    {
        element->paused = false;
    }
}
void jsb_del_proxy_for_jsobject(JSObject *obj)
{
	tHashJSObject *element = NULL;
	HASH_FIND_PTR(hash, &obj, element);
	if( element ) {		
		HASH_DEL(hash, element);
		free(element);
	}
}
void jsb_del_jsobject_for_proxy(void* proxy)
{
	tHashJSObject *element = NULL;
	HASH_FIND_PTR(reverse_hash, &proxy, element);
	if( element ) {		
		HASH_DEL(reverse_hash, element);
		free(element);
	}	
}
// Reverse hash: Proxy -> JSObject
JSObject* jsb_get_jsobject_for_proxy(void *proxy)
{
	tHashJSObject *element = NULL;
	HASH_FIND_PTR(reverse_hash, &proxy, element);
	
	if( element )
		return element->jsObject;
	return NULL;
}
// XXX: Passing "const O *" instead of "const O&" because HASH_FIND_IT requries the address of a pointer
// and, it is not possible to get the address of a reference
KDint32 ActionManager::getNumberOfRunningActionsInTarget ( const Object* pTarget ) const
{
    tHashElement *element = NULL;
    HASH_FIND_PTR(m_pTargets, &pTarget, element);
    if (element)
    {
        return element->actions ? element->actions->num : 0;
    }

    return 0;
}
Beispiel #25
0
// FIXME: Passing "const O *" instead of "const O&" because HASH_FIND_IT requires the address of a pointer
// and, it is not possible to get the address of a reference
ssize_t ActionManager::getNumberOfRunningActionsInTarget(const Node *target) const
{
    tHashElement *element = nullptr;
    HASH_FIND_PTR(_targets, &target, element);
    if (element)
    {
        return element->actions ? element->actions->num : 0;
    }

    return 0;
}
Beispiel #26
0
void xpl_free(void *ptr) {
    xpl_allocation_t *allocation_info = NULL;
    HASH_FIND_PTR(allocations, &ptr, allocation_info);

    if (allocation_info == NULL) {
        LOG_ERROR("Double-free detected %p (allocation table entry not found)", ptr);

        xpl_allocation_t *found, *tmp;
        LOG_DEBUG("Table:");
        HASH_ITER(hh, allocations, found, tmp) {
            LOG_DEBUG("> %p     %lu bytes", found->handle, (unsigned long)found->bytes);
        }
Beispiel #27
0
/**
 * Returns the ReferentEntry for the specified object or creates one and adds
 * it to the referents hash if none exists. referentsLock MUST be held.
 */
static ReferentEntry* getReferentEntryForObject(Env* env, Object* o) {
    void* key = (void*) GC_HIDE_POINTER(o); // Hide the pointer from the GC so that the key doesn't prevent the object from being GCed.
    ReferentEntry* referentEntry;
    HASH_FIND_PTR(referents, &key, referentEntry);
    if (!referentEntry) {
        // Object is not in the hashtable. Add it.
        referentEntry = allocateMemoryOfKind(env, sizeof(ReferentEntry), referentEntryGCKind);
        if (!referentEntry) return NULL; // OOM thrown
        referentEntry->key = key;
        HASH_ADD_PTR(referents, key, referentEntry);
    }
    return referentEntry;
}
Beispiel #28
0
size_t retreive_size(void *someaddr){
  size_t res;
  hash_t *elem = NULL;
  HASH_FIND_PTR(size_hash, &someaddr, elem);
  if(!elem){
    fprintf(stderr,"cannot find ptr %p to free!\n",someaddr);
    return 0;
  }

  res  = elem->size;
  if(get_verbose_level()>=DEBUG)
    printf("Retreiving (%p,%ld)\n",someaddr, res);

  HASH_DEL( size_hash, elem);
  return res;
}
static void account_realloc(void *p, void *ptr, size_t size)
{
	// Do not account itself
	no_hook = 1;

	// ptr == NULL is equivalent to malloc(size) 
	if (ptr == NULL) {
		account_alloc(p, size);
	}
	// size == 0 is equivalent to free(ptr), 
	// and p will be NULL
	else if (size == 0) {
		account_alloc(ptr, size);
	}
	// Now the real realloc
	else {
		log("Realloc: %p -> %d\n", ptr, size);

		// if ptr was moved previous area will be freed
		if (p != ptr) {
			log("Realloc: Replacing pointer %p to %p\n", ptr, p);
			account_alloc(ptr, 0);
			account_alloc(p, size);
		} else {
			struct malloc_item *found;
			int alloc_diff;

			HASH_FIND_PTR(HT, &ptr, found);
			if (found) {
				// alloc_diff may be negative when shrinking memory
				alloc_diff = size - found->size;

				mem_allocated += alloc_diff;
				found->size += alloc_diff;
				log("Realloc: diff %p -> %d\n", ptr, alloc_diff);
			} else {
				log("Reallocating unaccounted pointer %p\n", ptr);
			}
		}
	}

	log(" [[[:::  %d (%u) :::]]] \n", mem_allocated, HASH_COUNT(HT));

	no_hook = 0;
}
inline js_proxy_t *js_get_or_create_proxy(JSContext *cx, T *native_obj) {
    js_proxy_t *proxy;
    HASH_FIND_PTR(_native_js_global_ht, &native_obj, proxy);
    if (!proxy) {
        js_type_class_t *typeProxy = js_get_type_from_native<T>(native_obj);
        assert(typeProxy);
        JSObject* js_obj = JS_NewObject(cx, typeProxy->jsclass, typeProxy->proto, typeProxy->parentProto);
        JS_NEW_PROXY(proxy, native_obj, js_obj);
#ifdef DEBUG
        JS_AddNamedObjectRoot(cx, &proxy->obj, typeid(*native_obj).name());
#else
        JS_AddObjectRoot(cx, &proxy->obj);
#endif
        return proxy;
    } else {
        return proxy;
    }
    return NULL;
}