Back to index

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

Go to the source code of this file.

Defines

#define DROP_CLEAR_VALUE(jsdc, x)   if(x){jsd_DropValue(jsdc,x); x = NULL;}

Functions

JSBool jsd_IsValueObject (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueNumber (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueInt (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueDouble (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueString (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueBoolean (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueNull (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueVoid (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValuePrimitive (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueFunction (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_IsValueNative (JSDContext *jsdc, JSDValue *jsdval)
JSBool jsd_GetValueBoolean (JSDContext *jsdc, JSDValue *jsdval)
int32 jsd_GetValueInt (JSDContext *jsdc, JSDValue *jsdval)
jsdoublejsd_GetValueDouble (JSDContext *jsdc, JSDValue *jsdval)
JSStringjsd_GetValueString (JSDContext *jsdc, JSDValue *jsdval)
const char * jsd_GetValueFunctionName (JSDContext *jsdc, JSDValue *jsdval)
JSDValuejsd_NewValue (JSDContext *jsdc, jsval val)
void jsd_DropValue (JSDContext *jsdc, JSDValue *jsdval)
jsval jsd_GetValueWrappedJSVal (JSDContext *jsdc, JSDValue *jsdval)
static JSDProperty_newProperty (JSDContext *jsdc, JSPropertyDesc *pd, uintN additionalFlags)
static void _freeProps (JSDContext *jsdc, JSDValue *jsdval)
static JSBool _buildProps (JSDContext *jsdc, JSDValue *jsdval)
void jsd_RefreshValue (JSDContext *jsdc, JSDValue *jsdval)
uintN jsd_GetCountOfProperties (JSDContext *jsdc, JSDValue *jsdval)
JSDPropertyjsd_IterateProperties (JSDContext *jsdc, JSDValue *jsdval, JSDProperty **iterp)
JSDPropertyjsd_GetValueProperty (JSDContext *jsdc, JSDValue *jsdval, JSString *name)
JSDValuejsd_GetValuePrototype (JSDContext *jsdc, JSDValue *jsdval)
JSDValuejsd_GetValueParent (JSDContext *jsdc, JSDValue *jsdval)
JSDValuejsd_GetValueConstructor (JSDContext *jsdc, JSDValue *jsdval)
const char * jsd_GetValueClassName (JSDContext *jsdc, JSDValue *jsdval)
JSDValuejsd_GetPropertyName (JSDContext *jsdc, JSDProperty *jsdprop)
JSDValuejsd_GetPropertyValue (JSDContext *jsdc, JSDProperty *jsdprop)
JSDValuejsd_GetPropertyAlias (JSDContext *jsdc, JSDProperty *jsdprop)
uintN jsd_GetPropertyFlags (JSDContext *jsdc, JSDProperty *jsdprop)
uintN jsd_GetPropertyVarArgSlot (JSDContext *jsdc, JSDProperty *jsdprop)
void jsd_DropProperty (JSDContext *jsdc, JSDProperty *jsdprop)

Define Documentation

#define DROP_CLEAR_VALUE (   jsdc,
  x 
)    if(x){jsd_DropValue(jsdc,x); x = NULL;}

Definition at line 362 of file jsd_val.c.


Function Documentation

static JSBool _buildProps ( JSDContext jsdc,
JSDValue jsdval 
) [static]

Definition at line 330 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;
    JSPropertyDescArray pda;
    uintN i;

    JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
    JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
    JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));

    if(!JSVAL_IS_OBJECT(jsdval->val) || JSVAL_IS_NULL(jsdval->val))
        return JS_FALSE;

    if(!JS_GetPropertyDescArray(cx, JSVAL_TO_OBJECT(jsdval->val), &pda))
        return JS_FALSE;

    for(i = 0; i < pda.length; i++)
    {
        JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
        if(!prop)
        {
            _freeProps(jsdc, jsdval);
            break;
        }
        JS_APPEND_LINK(&prop->links, &jsdval->props);
    }
    JS_PutPropertyDescArray(cx, &pda);
    SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
    return !JS_CLIST_IS_EMPTY(&jsdval->props);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _freeProps ( JSDContext jsdc,
JSDValue jsdval 
) [static]

Definition at line 316 of file jsd_val.c.

{
    JSDProperty* jsdprop;

    while(jsdprop = (JSDProperty*)jsdval->props.next,
          jsdprop != (JSDProperty*)&jsdval->props)
    {
        JS_REMOVE_AND_INIT_LINK(&jsdprop->links);
        jsd_DropProperty(jsdc, jsdprop);
    }
    JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
    CLEAR_BIT_FLAG(jsdval->flags, GOT_PROPS);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static JSDProperty* _newProperty ( JSDContext jsdc,
JSPropertyDesc pd,
uintN  additionalFlags 
) [static]

Definition at line 287 of file jsd_val.c.

{
    JSDProperty* jsdprop;

    if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
        return NULL;

    JS_INIT_CLIST(&jsdprop->links);
    jsdprop->nref = 1;
    jsdprop->flags = pd->flags | additionalFlags;
    jsdprop->slot = pd->slot;

    if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
        goto new_prop_fail;

    if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
        goto new_prop_fail;

    if((jsdprop->flags & JSDPD_ALIAS) &&
       !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
        goto new_prop_fail;

    return jsdprop;
new_prop_fail:
    jsd_DropProperty(jsdc, jsdprop);
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void jsd_DropProperty ( JSDContext jsdc,
JSDProperty jsdprop 
)

Definition at line 619 of file jsd_val.c.

{
    JS_ASSERT(jsdprop->nref > 0);
    if(0 == --jsdprop->nref)
    {
        JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdprop->links));
        DROP_CLEAR_VALUE(jsdc, jsdprop->val);
        DROP_CLEAR_VALUE(jsdc, jsdprop->name);
        DROP_CLEAR_VALUE(jsdc, jsdprop->alias);
        free(jsdprop);
    }
}

Here is the caller graph for this function:

void jsd_DropValue ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 269 of file jsd_val.c.

{
    JS_ASSERT(jsdval->nref > 0);
    if(0 == --jsdval->nref)
    {
        jsd_RefreshValue(jsdc, jsdval);
        if(JSVAL_IS_GCTHING(jsdval->val))
            JS_RemoveRoot(jsdc->dumbContext, &jsdval->val);
        free(jsdval);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

uintN jsd_GetCountOfProperties ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 389 of file jsd_val.c.

{
    JSDProperty* jsdprop;
    uintN count = 0;

    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
        if(!_buildProps(jsdc, jsdval))
            return 0;

    for(jsdprop = (JSDProperty*)jsdval->props.next;
        jsdprop != (JSDProperty*)&jsdval->props;
        jsdprop = (JSDProperty*)jsdprop->links.next)
    {
        count++;
    }
    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetPropertyAlias ( JSDContext jsdc,
JSDProperty jsdprop 
)

Definition at line 599 of file jsd_val.c.

{
    if(jsdprop->alias)
        jsdprop->alias->nref++;
    return jsdprop->alias;
}

Here is the caller graph for this function:

uintN jsd_GetPropertyFlags ( JSDContext jsdc,
JSDProperty jsdprop 
)

Definition at line 607 of file jsd_val.c.

{
    return jsdprop->flags;
}

Here is the caller graph for this function:

JSDValue* jsd_GetPropertyName ( JSDContext jsdc,
JSDProperty jsdprop 
)

Definition at line 585 of file jsd_val.c.

{
    jsdprop->name->nref++;
    return jsdprop->name;
}

Here is the caller graph for this function:

JSDValue* jsd_GetPropertyValue ( JSDContext jsdc,
JSDProperty jsdprop 
)

Definition at line 592 of file jsd_val.c.

{
    jsdprop->val->nref++;
    return jsdprop->val;
}

Here is the caller graph for this function:

Definition at line 613 of file jsd_val.c.

{
    return jsdprop->slot;
}

Here is the caller graph for this function:

JSBool jsd_GetValueBoolean ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 172 of file jsd_val.c.

{
    jsval val = jsdval->val;
    if(!JSVAL_IS_BOOLEAN(val))
        return JS_FALSE;
    return JSVAL_TO_BOOLEAN(val);
}

Here is the caller graph for this function:

const char* jsd_GetValueClassName ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 567 of file jsd_val.c.

{
    jsval val = jsdval->val;
    if(!jsdval->className && JSVAL_IS_OBJECT(val))
    {
        JSObject* obj;
        if(!(obj = JSVAL_TO_OBJECT(val)))
            return NULL;
        if(JS_GET_CLASS(jsdc->dumbContext, obj))
            jsdval->className = JS_GET_CLASS(jsdc->dumbContext, obj)->name;
    }
    return jsdval->className;
}

Here is the caller graph for this function:

JSDValue* jsd_GetValueConstructor ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 542 of file jsd_val.c.

{
    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
    {
        JSObject* obj;
        JSObject* proto;
        JSObject* ctor;
        JS_ASSERT(!jsdval->ctor);
        SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        if(!(proto = JS_GetPrototype(jsdc->dumbContext,obj)))
            return NULL;
        if(!(ctor = JS_GetConstructor(jsdc->dumbContext,proto)))
            return NULL;
        jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
    }
    if(jsdval->ctor)
        jsdval->ctor->nref++;
    return jsdval->ctor;
}

Here is the call graph for this function:

Here is the caller graph for this function:

jsdouble* jsd_GetValueDouble ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 190 of file jsd_val.c.

{
    jsval val = jsdval->val;
    if(!JSVAL_IS_DOUBLE(val))
        return 0;
    return JSVAL_TO_DOUBLE(val);
}

Here is the caller graph for this function:

const char* jsd_GetValueFunctionName ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 225 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;
    JSFunction* fun;
    JSExceptionState* exceptionState;

    if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
    {
        exceptionState = JS_SaveExceptionState(cx);
        fun = JS_ValueToFunction(cx, jsdval->val);
        JS_RestoreExceptionState(cx, exceptionState);
        if(!fun)
            return NULL;
        jsdval->funName = JS_GetFunctionName(fun);
    }
    return jsdval->funName;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int32 jsd_GetValueInt ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 181 of file jsd_val.c.

{
    jsval val = jsdval->val;
    if(!JSVAL_IS_INT(val))
        return 0;
    return JSVAL_TO_INT(val);
}

Here is the caller graph for this function:

JSDValue* jsd_GetValueParent ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 520 of file jsd_val.c.

{
    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
    {
        JSObject* obj;
        JSObject* parent;
        JS_ASSERT(!jsdval->parent);
        SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        if(!(parent = JS_GetParent(jsdc->dumbContext,obj)))
            return NULL;
        jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
    }
    if(jsdval->parent)
        jsdval->parent->nref++;
    return jsdval->parent;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDProperty* jsd_GetValueProperty ( JSDContext jsdc,
JSDValue jsdval,
JSString name 
)

Definition at line 430 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;
    JSDProperty* jsdprop;
    JSDProperty* iter = NULL;
    JSObject* obj;
    uintN  attrs = 0;
    JSBool found;
    JSPropertyDesc pd;
    const jschar * nameChars;
    size_t nameLen;
    jsval val;

    if(!jsd_IsValueObject(jsdc, jsdval))
        return NULL;

    /* If we already have the prop, then return it */
    while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
    {
        JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
        if(propName && !JS_CompareStrings(propName, name))
            return jsdprop;
        JSD_DropProperty(jsdc, jsdprop);
    }
    /* Not found in property list, look it up explicitly */

    if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
        return NULL;

    nameChars = JS_GetStringChars(name);
    nameLen   = JS_GetStringLength(name);

    JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
    if (!found)
        return NULL;

    JS_ClearPendingException(cx);

    if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
    {
        if (JS_IsExceptionPending(cx))
        {
            if (!JS_GetPendingException(cx, &pd.value))
                return NULL;
            pd.flags = JSPD_EXCEPTION;
        }
        else
        {
            pd.flags = JSPD_ERROR;
            pd.value = JSVAL_VOID;
        }
    }
    else
    {
        pd.value = val;
    }

    pd.id = STRING_TO_JSVAL(name);
    pd.alias = pd.slot = pd.spare = 0;
    pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
        | (attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0
        | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;

    return _newProperty(jsdc, &pd, JSDPD_HINTED);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_GetValuePrototype ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 498 of file jsd_val.c.

{
    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
    {
        JSObject* obj;
        JSObject* proto;
        JS_ASSERT(!jsdval->proto);
        SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        if(!(proto = JS_GetPrototype(jsdc->dumbContext, obj)))
            return NULL;
        jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
    }
    if(jsdval->proto)
        jsdval->proto->nref++;
    return jsdval->proto;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSString* jsd_GetValueString ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 199 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;
    JSExceptionState* exceptionState;

    if(!jsdval->string)
    {
        /* if the jsval is a string, then we don't need to double root it */
        if(JSVAL_IS_STRING(jsdval->val))
            jsdval->string = JSVAL_TO_STRING(jsdval->val);
        else
        {
            exceptionState = JS_SaveExceptionState(cx);
            jsdval->string = JS_ValueToString(cx, jsdval->val);
            JS_RestoreExceptionState(cx, exceptionState);
            if(jsdval->string)
            {
                if(!JS_AddNamedRoot(cx, &jsdval->string, "ValueString"))
                    jsdval->string = NULL;
            }
        }
    }
    return jsdval->string;
}

Here is the call graph for this function:

Here is the caller graph for this function:

jsval jsd_GetValueWrappedJSVal ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 282 of file jsd_val.c.

{
    return jsdval->val;
}

Here is the caller graph for this function:

JSBool jsd_IsValueBoolean ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 116 of file jsd_val.c.

{
    return JSVAL_IS_BOOLEAN(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueDouble ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 104 of file jsd_val.c.

{
    return JSVAL_IS_DOUBLE(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueFunction ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 140 of file jsd_val.c.

{
    return !JSVAL_IS_PRIMITIVE(jsdval->val) &&
           JS_ObjectIsFunction(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsValueInt ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 98 of file jsd_val.c.

{
    return JSVAL_IS_INT(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueNative ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 147 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;
    jsval val = jsdval->val;
    JSFunction* fun;
    JSExceptionState* exceptionState;

    if(jsd_IsValueFunction(jsdc, jsdval))
    {
        exceptionState = JS_SaveExceptionState(cx);
        fun = JS_ValueToFunction(cx, val);
        JS_RestoreExceptionState(cx, exceptionState);
        if(!fun)
        {
            JS_ASSERT(0);
            return JS_FALSE;
        }
        return JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
    }
    return !JSVAL_IS_PRIMITIVE(val);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool jsd_IsValueNull ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 122 of file jsd_val.c.

{
    return JSVAL_IS_NULL(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueNumber ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 92 of file jsd_val.c.

{
    return JSVAL_IS_NUMBER(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueObject ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 86 of file jsd_val.c.

{
    return JSVAL_IS_OBJECT(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValuePrimitive ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 134 of file jsd_val.c.

{
    return JSVAL_IS_PRIMITIVE(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueString ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 110 of file jsd_val.c.

{
    return JSVAL_IS_STRING(jsdval->val);
}

Here is the caller graph for this function:

JSBool jsd_IsValueVoid ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 128 of file jsd_val.c.

{
    return JSVAL_IS_VOID(jsdval->val);
}

Here is the caller graph for this function:

JSDProperty* jsd_IterateProperties ( JSDContext jsdc,
JSDValue jsdval,
JSDProperty **  iterp 
)

Definition at line 408 of file jsd_val.c.

{
    JSDProperty* jsdprop = *iterp;
    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)))
    {
        JS_ASSERT(!jsdprop);
        if(!_buildProps(jsdc, jsdval))
            return NULL;
    }

    if(!jsdprop)
        jsdprop = (JSDProperty*)jsdval->props.next;
    if(jsdprop == (JSDProperty*)&jsdval->props)
        return NULL;
    *iterp = (JSDProperty*)jsdprop->links.next;

    JS_ASSERT(jsdprop);
    jsdprop->nref++;
    return jsdprop;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSDValue* jsd_NewValue ( JSDContext jsdc,
jsval  val 
)

Definition at line 246 of file jsd_val.c.

{
    JSDValue* jsdval;

    if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
        return NULL;

    if(JSVAL_IS_GCTHING(val))
    {
        if(!JS_AddNamedRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"))
        {
            free(jsdval);
            return NULL;
        }
    }
    jsdval->val  = val;
    jsdval->nref = 1;
    JS_INIT_CLIST(&jsdval->props);

    return jsdval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void jsd_RefreshValue ( JSDContext jsdc,
JSDValue jsdval 
)

Definition at line 365 of file jsd_val.c.

{
    JSContext* cx = jsdc->dumbContext;

    if(jsdval->string)
    {
        /* if the jsval is a string, then we didn't need to root the string */
        if(!JSVAL_IS_STRING(jsdval->val))
            JS_RemoveRoot(cx, &jsdval->string);
        jsdval->string = NULL;
    }

    jsdval->funName = NULL;
    jsdval->className = NULL;
    DROP_CLEAR_VALUE(jsdc, jsdval->proto);
    DROP_CLEAR_VALUE(jsdc, jsdval->parent);
    DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
    _freeProps(jsdc, jsdval);
    jsdval->flags = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function: