Back to index

lightning-sunbird  0.9+nobinonly
Functions
jsd_stak.c File Reference
#include "jsd.h"

Go to the source code of this file.

Functions

static JSDStackFrameInfo_addNewFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSScript *script, jsuword pc, JSStackFrame *fp)
static void _destroyFrame (JSDStackFrameInfo *jsdframe)
JSDThreadStatejsd_NewThreadState (JSDContext *jsdc, JSContext *cx)
void jsd_DestroyThreadState (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
uintN jsd_GetCountOfStackFrames (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSDStackFrameInfojsd_GetStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSContextjsd_GetJSContext (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSDStackFrameInfojsd_GetCallingStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSDScriptjsd_GetScriptForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
jsuword jsd_GetPCForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSDValuejsd_GetCallObjectForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSDValuejsd_GetScopeChainForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSDValuejsd_GetThisForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
const char * jsd_GetNameForStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSBool jsd_IsStackFrameNative (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSBool jsd_IsStackFrameDebugger (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSBool jsd_IsStackFrameConstructing (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
JSBool jsd_EvaluateUCScriptInStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe, const jschar *bytes, uintN length, const char *filename, uintN lineno, JSBool eatExceptions, jsval *rval)
JSBool jsd_EvaluateScriptInStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe, const char *bytes, uintN length, const char *filename, uintN lineno, JSBool eatExceptions, jsval *rval)
JSStringjsd_ValToStringInStackFrame (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe, jsval val)
JSBool jsd_IsValidThreadState (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSBool jsd_IsValidFrameInThreadState (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDStackFrameInfo *jsdframe)
static JSContext_getContextForThreadState (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSDValuejsd_GetException (JSDContext *jsdc, JSDThreadState *jsdthreadstate)
JSBool jsd_SetException (JSDContext *jsdc, JSDThreadState *jsdthreadstate, JSDValue *jsdval)

Function Documentation

static JSDStackFrameInfo* _addNewFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSScript script,
jsuword  pc,
JSStackFrame fp 
) [static]

Definition at line 59 of file jsd_stak.c.

{
    JSDStackFrameInfo* jsdframe;
    JSDScript*         jsdscript = NULL;

    if (!JS_IsNativeFrame(jsdthreadstate->context, fp))
    {
        JSD_LOCK_SCRIPTS(jsdc);
        jsdscript = jsd_FindJSDScript(jsdc, script);
        JSD_UNLOCK_SCRIPTS(jsdc);
        if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
                           !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
        {
            return NULL;
        }

        if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
            jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
    }
    
    jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
    if( ! jsdframe )
        return NULL;

    jsdframe->jsdthreadstate = jsdthreadstate;
    jsdframe->jsdscript      = jsdscript;
    jsdframe->pc             = pc;
    jsdframe->fp             = fp;

    JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
    jsdthreadstate->stackDepth++;

    return jsdframe;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _destroyFrame ( JSDStackFrameInfo jsdframe) [static]

Definition at line 99 of file jsd_stak.c.

{
    /* kill any alloc'd objects in frame here... */

    if( jsdframe )
        free(jsdframe);
}

Here is the caller graph for this function:

static JSContext* _getContextForThreadState ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
) [static]

Definition at line 567 of file jsd_stak.c.

{
    JSBool valid;
    JSD_LOCK_THREADSTATES(jsdc);
    valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
    JSD_UNLOCK_THREADSTATES(jsdc);
    if( valid )
        return jsdthreadstate->context;
    return NULL;
}        

Here is the call graph for this function:

Here is the caller graph for this function:

void jsd_DestroyThreadState ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 170 of file jsd_stak.c.

{
    JSDStackFrameInfo* jsdframe;
    JSCList* list;

    JS_ASSERT(jsdthreadstate);
    JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);

    JSD_LOCK_THREADSTATES(jsdc);
    JS_REMOVE_LINK(&jsdthreadstate->links);
    JSD_UNLOCK_THREADSTATES(jsdc);

    list = &jsdthreadstate->stack;
    while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
    {
        JS_REMOVE_LINK(&jsdframe->links);
        _destroyFrame(jsdframe);
    }
    free(jsdthreadstate);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_EvaluateScriptInStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe,
const char *  bytes,
uintN  length,
const char *  filename,
uintN  lineno,
JSBool  eatExceptions,
jsval rval 
)

Definition at line 465 of file jsd_stak.c.

{
    JSBool retval;
    JSBool valid;
    JSExceptionState* exceptionState = NULL;
    JSContext *cx;

    JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);

    JSD_LOCK_THREADSTATES(jsdc);
    valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
    JSD_UNLOCK_THREADSTATES(jsdc);

    if (!valid)
        return JS_FALSE;

    cx = jsdthreadstate->context;
    JS_ASSERT(cx);

    if (eatExceptions)
        exceptionState = JS_SaveExceptionState(cx);
    JS_ClearPendingException(cx);
    jsd_StartingEvalUsingFilename(jsdc, filename);
    retval = JS_EvaluateInStackFrame(cx, jsdframe->fp, bytes, length,
                                     filename, lineno, rval);
    jsd_FinishedEvalUsingFilename(jsdc, filename);
    if (eatExceptions)
        JS_RestoreExceptionState(cx, exceptionState);

    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_EvaluateUCScriptInStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe,
const jschar bytes,
uintN  length,
const char *  filename,
uintN  lineno,
JSBool  eatExceptions,
jsval rval 
)

Definition at line 427 of file jsd_stak.c.

{
    JSBool retval;
    JSBool valid;
    JSExceptionState* exceptionState = NULL;
    JSContext* cx;

    JS_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);

    JSD_LOCK_THREADSTATES(jsdc);
    valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
    JSD_UNLOCK_THREADSTATES(jsdc);

    if( ! valid )
        return JS_FALSE;

    cx = jsdthreadstate->context;
    JS_ASSERT(cx);

    if (eatExceptions)
        exceptionState = JS_SaveExceptionState(cx);
    JS_ClearPendingException(cx);
    jsd_StartingEvalUsingFilename(jsdc, filename);
    retval = JS_EvaluateUCInStackFrame(cx, jsdframe->fp, bytes, length, 
                                       filename, lineno, rval);
    jsd_FinishedEvalUsingFilename(jsdc, filename);
    if (eatExceptions)
        JS_RestoreExceptionState(cx, exceptionState);

    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDStackFrameInfo* jsd_GetCallingStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 234 of file jsd_stak.c.

{
    JSDStackFrameInfo* nextjsdframe = NULL;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
        if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
            nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);

    JSD_UNLOCK_THREADSTATES(jsdc);

    return nextjsdframe;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetCallObjectForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 286 of file jsd_stak.c.

{
    JSObject* obj;
    JSDValue* jsdval = NULL;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        obj = JS_GetFrameCallObject(jsdthreadstate->context, jsdframe->fp); 
        if(obj)                                                             
            jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));              
    }

    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

uintN jsd_GetCountOfStackFrames ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 192 of file jsd_stak.c.

{
    uintN count = 0;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
        count = jsdthreadstate->stackDepth;

    JSD_UNLOCK_THREADSTATES(jsdc);

    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetException ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 579 of file jsd_stak.c.

{
    JSContext* cx;
    jsval val;

    if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
        return NULL;

    if(JS_GetPendingException(cx, &val))
        return jsd_NewValue(jsdc, val);
    return NULL;
}        

Here is the call graph for this function:

Here is the caller graph for this function:

JSContext* jsd_GetJSContext ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 221 of file jsd_stak.c.

{
    JSContext* cx = NULL;

    JSD_LOCK_THREADSTATES(jsdc);
    if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
        cx = jsdthreadstate->context;
    JSD_UNLOCK_THREADSTATES(jsdc);

    return cx;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* jsd_GetNameForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 350 of file jsd_stak.c.

{
    const char *rv = NULL;
    
    JSD_LOCK_THREADSTATES(jsdc);
    
    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        JSFunction *fun = JS_GetFrameFunction (jsdthreadstate->context,
                                               jsdframe->fp);
        if (fun)
            rv = JS_GetFunctionName (fun);
    }
    
    JSD_UNLOCK_THREADSTATES(jsdc);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

jsuword jsd_GetPCForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 269 of file jsd_stak.c.

{
    jsuword pc = 0;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
        pc = jsdframe->pc;

    JSD_UNLOCK_THREADSTATES(jsdc);

    return pc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetScopeChainForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 308 of file jsd_stak.c.

{
    JSObject* obj;
    JSDValue* jsdval = NULL;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        obj = JS_GetFrameScopeChain(jsdthreadstate->context, jsdframe->fp); 
        if(obj)                                                             
            jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));              
    }

    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDScript* jsd_GetScriptForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 252 of file jsd_stak.c.

{
    JSDScript* jsdscript = NULL;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
        jsdscript = jsdframe->jsdscript;

    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdscript;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDStackFrameInfo* jsd_GetStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 207 of file jsd_stak.c.

{
    JSDStackFrameInfo* jsdframe = NULL;

    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
        jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdframe;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetThisForStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 330 of file jsd_stak.c.

{
    JSObject* obj;
    JSDValue* jsdval = NULL;
    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        obj = JS_GetFrameThis(jsdthreadstate->context, jsdframe->fp);
        if(obj)
            jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
    }

    JSD_UNLOCK_THREADSTATES(jsdc);
    return jsdval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsStackFrameConstructing ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 410 of file jsd_stak.c.

{
    JSBool rv = JS_TRUE;
    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        rv = JS_IsConstructorFrame(jsdthreadstate->context, jsdframe->fp);
    }

    JSD_UNLOCK_THREADSTATES(jsdc);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsStackFrameDebugger ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 393 of file jsd_stak.c.

{
    JSBool rv = JS_TRUE;
    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        rv = JS_IsDebuggerFrame(jsdthreadstate->context, jsdframe->fp);
    }

    JSD_UNLOCK_THREADSTATES(jsdc);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsStackFrameNative ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 371 of file jsd_stak.c.

{
    JSBool rv;
    
    JSD_LOCK_THREADSTATES(jsdc);

    if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
    {
        rv = JS_IsNativeFrame(jsdthreadstate->context, jsdframe->fp);
    }
    else
    {
        rv = JS_FALSE;
    }

    JSD_UNLOCK_THREADSTATES(jsdc);
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsValidFrameInThreadState ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe 
)

Definition at line 549 of file jsd_stak.c.

{
    JS_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));

    if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
        return JS_FALSE;
    if( jsdframe->jsdthreadstate != jsdthreadstate )
        return JS_FALSE;

    JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
    JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
    
    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsValidThreadState ( JSDContext jsdc,
JSDThreadState jsdthreadstate 
)

Definition at line 531 of file jsd_stak.c.

{
    JSDThreadState *cur;

    JS_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );

    for( cur = (JSDThreadState*)jsdc->threadsStates.next;
         cur != (JSDThreadState*)&jsdc->threadsStates;
         cur = (JSDThreadState*)cur->links.next ) 
    {
        if( cur == jsdthreadstate )
            return JS_TRUE;
    }
    return JS_FALSE;
}    

Here is the caller graph for this function:

Definition at line 108 of file jsd_stak.c.

{
    JSDThreadState* jsdthreadstate;
    JSStackFrame *  iter = NULL;
    JSStackFrame *  fp;

    jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
    if( ! jsdthreadstate )
        return NULL;

    jsdthreadstate->context = cx;
    jsdthreadstate->thread = JSD_CURRENT_THREAD();
    JS_INIT_CLIST(&jsdthreadstate->stack);
    jsdthreadstate->stackDepth = 0;

    while( NULL != (fp = JS_FrameIterator(cx, &iter)) )
    {
        JSScript* script = JS_GetFrameScript(cx, fp);
        jsuword  pc = (jsuword) JS_GetFramePC(cx, fp);

        /*
         * don't construct a JSDStackFrame for dummy frames (those without a
         * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
         * isn't set.
         */
        if (JS_GetFrameThis(cx, fp) &&
            ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) ||
             !JS_IsNativeFrame(cx, fp)))
        {
            JSDStackFrameInfo *frame;

            frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp );

            if ((jsdthreadstate->stackDepth == 0 && !frame) ||
                (jsdthreadstate->stackDepth == 1 && frame &&
                 frame->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript)))
            {
                /*
                 * if we failed to create the first frame, or the top frame
                 * is not enabled for debugging, fail the entire thread state.
                 */
                JS_INIT_CLIST(&jsdthreadstate->links);
                jsd_DestroyThreadState(jsdc, jsdthreadstate);
                return NULL;
            }
        }
    }

    if (jsdthreadstate->stackDepth == 0)
    {
        free(jsdthreadstate);
        return NULL;
    }
    
    JSD_LOCK_THREADSTATES(jsdc);
    JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
    JSD_UNLOCK_THREADSTATES(jsdc);

    return jsdthreadstate;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_SetException ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDValue jsdval 
)

Definition at line 593 of file jsd_stak.c.

{
    JSContext* cx;

    if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
        return JS_FALSE;

    if(jsdval)
        JS_SetPendingException(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
    else
        JS_ClearPendingException(cx);
    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSString* jsd_ValToStringInStackFrame ( JSDContext jsdc,
JSDThreadState jsdthreadstate,
JSDStackFrameInfo jsdframe,
jsval  val 
)

Definition at line 503 of file jsd_stak.c.

{
    JSBool valid;
    JSString* retval;
    JSExceptionState* exceptionState;
    JSContext* cx;

    JSD_LOCK_THREADSTATES(jsdc);
    valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
    JSD_UNLOCK_THREADSTATES(jsdc);

    if( ! valid )
        return NULL;

    cx = jsdthreadstate->context;
    JS_ASSERT(cx);

    exceptionState = JS_SaveExceptionState(cx);
    retval = JS_ValueToString(cx, val);
    JS_RestoreExceptionState(cx, exceptionState);

    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function: