Skip to content

Commit

Permalink
Check for functions containing both return; and return <obj>;
Browse files Browse the repository at this point in the history
This check is quite simplistic; in particular, it does not
perform an actual flow analysis.
  • Loading branch information
fingolfin committed Sep 21, 2017
1 parent 53a9d36 commit bb17b68
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
21 changes: 21 additions & 0 deletions src/calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ typedef Obj (* ObjFunc_6ARGS) (Obj self, Obj a1, Obj a2, Obj a3, Obj a4, Obj a5,
** 'NAMI_FUNC(<func>,<i>)' is the name of the <i>-th local variable.
**
** 'PROF_FUNC(<func>)' is the profiling information bag.
** 'RETURNS_FUNC(<func>)' is space used during coding to detect
** functions that contain both return and return <obj>;
** it's actually the same space as PROF_FUNC since that
** is never needed at coding time
** 'FUNC_RETURNS_OBJ' and 'FUNCS_RETURNS_VOID' are two different bits used
** for this
**
** 'NLOC_FUNC(<func>)' is the number of local variables of the interpreted
** function <func>.
Expand Down Expand Up @@ -163,6 +169,11 @@ static inline Obj PROF_FUNC(Obj func)
return FUNC_HEADER(func)->prof;
}

static inline UInt RETURNS_FUNC(Obj func)
{
return (UInt)FUNC_HEADER(func)->prof;
}

static inline UInt NLOC_FUNC(Obj func)
{
return FUNC_HEADER(func)->nloc;
Expand Down Expand Up @@ -215,6 +226,11 @@ static inline void SET_PROF_FUNC(Obj func, Obj prof)
FUNC_HEADER(func)->prof = prof;
}

static inline void SET_RETURNS_FUNC(Obj func, UInt val)
{
FUNC_HEADER(func)->prof = (Obj)val;
}

static inline void SET_NLOC_FUNC(Obj func, UInt nloc)
{
FUNC_HEADER(func)->nloc = nloc;
Expand Down Expand Up @@ -246,6 +262,11 @@ static inline void SET_LCKS_FUNC(Obj func, Obj locks)

#define SIZE_FUNC sizeof(FunctionHeader)

enum {
FUNC_RETURNS_OBJ = 1L,
FUNC_RETURNS_VOID = 2L,
};

#define HDLR_0ARGS(func) ((ObjFunc_0ARGS)HDLR_FUNC(func,0))
#define HDLR_1ARGS(func) ((ObjFunc_1ARGS)HDLR_FUNC(func,1))
#define HDLR_2ARGS(func) ((ObjFunc_2ARGS)HDLR_FUNC(func,2))
Expand Down
22 changes: 20 additions & 2 deletions src/code.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ void CodeFuncExprBegin (
/* give it a body */
body = NewBag( T_BODY, 1024*sizeof(Stat) );
SET_BODY_FUNC( fexp, body );
SET_RETURNS_FUNC( fexp, 0 );
CHANGED_BAG( fexp );

/* record where we are reading from */
Expand Down Expand Up @@ -842,7 +843,13 @@ void CodeFuncExprEnd (
/* get the function expression */
fexp = CURR_FUNC();
assert(!STATE(LoopNesting));


if ((RETURNS_FUNC(fexp) & (FUNC_RETURNS_OBJ | FUNC_RETURNS_VOID)) ==
(FUNC_RETURNS_OBJ | FUNC_RETURNS_VOID)) {
SyntaxWarning("Function contains both 'return <obj>;' and 'return;'");
}
SET_RETURNS_FUNC(fexp, 0);

/* get the body of the function */
/* push an additional return-void-statement if neccessary */
/* the function interpreters depend on each function ``returning'' */
Expand Down Expand Up @@ -1440,6 +1447,12 @@ void CodeReturnObj ( void )
expr = PopExpr();
ADDR_STAT(stat)[0] = expr;

// record that this function returned an object at least once, unless
// this is actually a 'TryNextMethod()' in disguise
if ( ! (TNUM_EXPR(expr) == T_REF_GVAR &&
ADDR_EXPR(expr)[0] == (Expr)GVarName( "TRY_NEXT_METHOD" )) )
SET_RETURNS_FUNC(CURR_FUNC(), RETURNS_FUNC(CURR_FUNC()) | FUNC_RETURNS_OBJ);

/* push the return-statement */
PushStat( stat );
}
Expand All @@ -1463,6 +1476,9 @@ void CodeReturnVoid ( void )
/* allocate the return-statement */
stat = NewStat( T_RETURN_VOID, 0 * sizeof(Expr) );

// record that this function returned void at least once
SET_RETURNS_FUNC(CURR_FUNC(), RETURNS_FUNC(CURR_FUNC()) | FUNC_RETURNS_VOID);

/* push the return-statement */
PushStat( stat );
}
Expand All @@ -1472,9 +1488,11 @@ void CodeReturnVoidWhichIsNotProfiled ( void )
Stat stat; /* return-statement, result */

/* allocate the return-statement, without profile information */

stat = NewStatWithProf( T_RETURN_VOID, 0 * sizeof(Expr), 0, 0 );

// record that this function returned void at least once
SET_RETURNS_FUNC(CURR_FUNC(), RETURNS_FUNC(CURR_FUNC()) | FUNC_RETURNS_VOID);

/* push the return-statement */
PushStat( stat );
}
Expand Down

0 comments on commit bb17b68

Please sign in to comment.