I've been working on polishing up my JSON code for my ECMAScript runtime and I decided to run an experiment. The following str function has 4 logical steps which I've broken up into functions and marked them inline.
and private str (state:StringifyState) (key:string) (holder:IObject) : IDynamic =
    let inline fourth (value:IDynamic) =
        match value.TypeCode with
        | LanguageTypeCode.Null -> 
            state.environment.CreateString "null" :> IDynamic
        | LanguageTypeCode.Boolean -> 
            let v = value :?> IBoolean
            state.environment.CreateString (if v.BaseValue then "true" else "false") :> IDynamic
        | LanguageTypeCode.String -> 
            let v = value :?> IString
            state.environment.CreateString (quote v.BaseValue) :> IDynamic
        | LanguageTypeCode.Number -> 
            let v = value :?> INumber
            if not (Double.IsInfinity(v.BaseValue)) 
            then v.ConvertToString() :> IDynamic 
            else state.environment.CreateString "null" :> IDynamic
        | LanguageTypeCode.Object -> 
            let v = value :?> IObject
            let v = if v.Class = "Array" then ja state v else jo state v 
            state.environment.CreateString v :> IDynamic
        | _ -> 
            state.environment.Undefined :> IDynamic
    let inline third (value:IDynamic) =
        match value.TypeCode with
        | LanguageTypeCode.Object ->
            let v = value :?> IObject
            match v.Class with
            | "Number" -> 
                fourth (v.ConvertToNumber())
            | "String" ->
                fourth (v.ConvertToString())
            | "Boolean" ->
                fourth (v.ConvertToBoolean())
            | _ -> 
                fourth value
        | _ -> 
            fourth value
    let inline second (value:IDynamic) =
        match state.replacerFunction with
        | :? ICallable as f ->
            let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic; value |])
            let value = f.Call (state.environment, holder :> IDynamic, args)
            third value
        | _ -> 
            third value 
    let inline first (value:IDynamic) =
        match value with
        | :? IObject as v ->
            let toJSON = v.Get "toJSON"
            match toJSON with
            | :? ICallable as f ->
                let args = state.environment.CreateArgs ([| state.environment.CreateString key :> IDynamic |])
                let value = f.Call (state.environment, value, args) 
                second value
            | _ -> 
                second value
        | _ -> 
            second value
    first (holder.Get key)
I compiled with full optimizations and opened up the resulting assembly with Reflector to see the results.
[CompilationArgumentCounts(new int[] { 1, 1, 1 })]
internal static IDynamic str(StringifyState state, string key, IObject holder)
{
    IObject obj3;
    ICallable callable;
    ICallable callable2;
    IArgs args;
    IDynamic dynamic3;
    IDynamic dynamic4;
    ICallable callable3;
    IDynamic dynamic5;
    IBoolean flag;
    IString str;
    INumber number;
    IObject obj4;
    string str2;
    INumber number2;
    IObject obj5;
    string str3;
    IString str4;
    IBoolean flag2;
    IDynamic thisBinding = holder.Get(key);
    IObject obj2 = thisBinding as IObject;
    if (obj2 == null)
    {
        callable = state.replacerFunction@ as ICallable;
        if (callable == null)
        {
            switch (thisBinding.TypeCode)
            {
                case LanguageTypeCode.Object:
                    obj3 = (IObject) thisBinding;
                    str2 = obj3.Class;
                    if (!string.Equals(str2, "Number"))
                    {
                        if (string.Equals(str2, "String"))
                        {
                            dynamic3 = obj3.ConvertToString();
                            switch (dynamic3.TypeCode)
                            {
                                case LanguageTypeCode.Null:
                                    return (IDynamic) state.environment@.CreateString("null");
                                case LanguageTypeCode.Boolean:
                                    flag = (IBoolean) dynamic3;
                                    return (IDynamic) state.environment@.CreateString(!flag.BaseValue ? "false" : "true");
                                case LanguageTypeCode.String:
                                    str4 = (IString) dynamic3;
                                    return (IDynamic) state.environment@.CreateString(quote(str4.BaseValue));
                                case LanguageTypeCode.Number:
                                    number = (INumber) dynamic3;
                                    if (double.IsInfinity(number.BaseValue))
                                    {
                                        return (IDynamic) state.environment@.CreateString("null");
                                    }
                                    return (IDynamic) number.ConvertToString();
    // ... I removed a large amount of code. 
    return (IDynamic) state.environment@.Undefined;
}
Clearly the inline modifier is quite literal. The code is quite huge and with some preliminary tests is very efficient. One might consider throwing inline on all of their functions if they didn't care about the size of the resulting assemblies. What are some guidelines I can follow to know when the use of inline is appropriate? If possible I would like to avoid having to measure performance every single time to determine this.
 
     
    