NO_INLINE JsVar *jspeFunctionCall(JsVar *function, JsVar *functionName, JsVar *thisArg, bool isParsing, int argCount, JsVar **argPtr) {
  if (JSP_SHOULD_EXECUTE && !function) {
    if (functionName)
      jsExceptionHere(JSET_ERROR, "Function %q not found!", functionName);
    else
      jsExceptionHere(JSET_ERROR, "Function not found!", functionName);
    return 0;
  }

  if (JSP_SHOULD_EXECUTE) if (!jspCheckStackPosition()) return 0; // try and ensure that we won't overflow our stack

  if (JSP_SHOULD_EXECUTE && function) {
    JsVar *returnVar = 0;

    if (!jsvIsFunction(function)) {
      jsExceptionHere(JSET_ERROR, "Expecting a function to call, got %t", function);
      return 0;
    }
    JsVar *thisVar = jsvLockAgainSafe(thisArg);
    if (isParsing) JSP_MATCH('(');

    /* Ok, so we have 4 options here.
     *
     * 1: we're native.
     *   a) args have been pre-parsed, which is awesome
     *   b) we have to parse our own args into an array
     * 2: we're not native
     *   a) args were pre-parsed and we have to populate the function
     *   b) we parse our own args, which is possibly better
     */
    if (jsvIsNativeFunction(function)) { // ------------------------------------- NATIVE
      unsigned int argPtrSize = 0;
      int boundArgs = 0;
      // Add 'bound' parameters if there were any
      JsvObjectIterator it;
      jsvObjectIteratorNew(&it, function);
      JsVar *param = jsvObjectIteratorGetKey(&it);
      while (jsvIsFunctionParameter(param)) {
        if ((unsigned)argCount>=argPtrSize) {
          // allocate more space on stack if needed
          unsigned int newArgPtrSize = (argPtrSize?argPtrSize:(unsigned int)argCount)*4;
          size_t newArgPtrByteSize = sizeof(JsVar*)*newArgPtrSize;
          if (jsuGetFreeStack() < 256+newArgPtrByteSize) {
            jsExceptionHere(JSET_ERROR, "Insufficient stack for this many arguments");
            jsvUnLock(thisVar);
            return 0;
          }
          JsVar **newArgPtr = (JsVar**)alloca(newArgPtrByteSize);
          memcpy(newArgPtr, argPtr, (unsigned)argCount*sizeof(JsVar*));
          argPtr = newArgPtr;
          argPtrSize = newArgPtrSize;
        }
        // if we already had arguments - shift them up...
        int i;
        for (i=argCount-1;i>=boundArgs;i--)
          argPtr[i+1] = argPtr[i];
        // add bound argument
        argPtr[boundArgs] = jsvSkipName(param);
        argCount++;
        boundArgs++;
        jsvUnLock(param);
        jsvObjectIteratorNext(&it);
        param = jsvObjectIteratorGetKey(&it);
      }
      // check if 'this' was defined
      while (param) {
        if (jsvIsStringEqual(param, JSPARSE_FUNCTION_THIS_NAME)) {
          jsvUnLock(thisVar);
          thisVar = jsvSkipName(param);
          break;
        }
        jsvUnLock(param);
        jsvObjectIteratorNext(&it);
        param = jsvObjectIteratorGetKey(&it);
      }
      jsvUnLock(param);
      jsvObjectIteratorFree(&it);

      // Now, if we're parsing add the rest of the arguments
      int allocatedArgCount = boundArgs;
      if (isParsing) {
        while (!JSP_HAS_ERROR && lex->tk!=')' && lex->tk!=LEX_EOF) {
          if ((unsigned)argCount>=argPtrSize) {
            // allocate more space on stack
            unsigned int newArgPtrSize = argPtrSize?argPtrSize*4:16;
            JsVar **newArgPtr = (JsVar**)alloca(sizeof(JsVar*)*newArgPtrSize);
            memcpy(newArgPtr, argPtr, (unsigned)argCount*sizeof(JsVar*));
            argPtr = newArgPtr;
            argPtrSize = newArgPtrSize;
          }
          argPtr[argCount++] = jsvSkipNameAndUnLock(jspeAssignmentExpression());
          if (lex->tk!=')') JSP_MATCH_WITH_CLEANUP_AND_RETURN(',',jsvUnLockMany((unsigned)argCount, argPtr);jsvUnLock(thisVar);, 0);
        }

        JSP_MATCH(')');
        allocatedArgCount = argCount;
      }

      void *nativePtr = jsvGetNativeFunctionPtr(function);

      JsVar *oldThisVar = execInfo.thisVar;
      if (thisVar)
        execInfo.thisVar = jsvRef(thisVar);
      else {
        if (nativePtr==jswrap_eval) { // eval gets to use the current scope
          /* Note: proper JS has some utterly insane code that depends on whether
           * eval is an lvalue or not:
           *
           * http://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript
           *
           * Doing this in Espruino is quite an upheaval for that one
           * slightly insane case - so it's not implemented. */
          if (execInfo.thisVar) execInfo.thisVar = jsvRef(execInfo.thisVar);
        } else {
          execInfo.thisVar = jsvRef(execInfo.root); // 'this' should always default to root
        }
      }



      if (nativePtr && !JSP_HAS_ERROR) {
        returnVar = jsnCallFunction(nativePtr, function->varData.native.argTypes, thisVar, argPtr, argCount);
        assert(!jsvIsName(returnVar));
      } else {
        returnVar = 0;
      }

      // unlock values if we locked them
      jsvUnLockMany((unsigned)allocatedArgCount, argPtr);

      /* Return to old 'this' var. No need to unlock as we never locked before */
      if (execInfo.thisVar) jsvUnRef(execInfo.thisVar);
      execInfo.thisVar = oldThisVar;

    } else { // ----------------------------------------------------- NOT NATIVE
      // create a new symbol table entry for execution of this function
      // OPT: can we cache this function execution environment + param variables?
      // OPT: Probably when calling a function ONCE, use it, otherwise when recursing, make new?
      JsVar *functionRoot = jsvNewWithFlags(JSV_FUNCTION);
      if (!functionRoot) { // out of memory
        jspSetError(false);
        jsvUnLock(thisVar);
        return 0;
      }

      JsVar *functionScope = 0;
      JsVar *functionCode = 0;
      JsVar *functionInternalName = 0;
#ifndef ESPR_NO_LINE_NUMBERS
      uint16_t functionLineNumber = 0;
#endif

      /** NOTE: We expect that the function object will have:
       *
       *  * Parameters
       *  * Code/Scope/Name
       *
       * IN THAT ORDER.
       */
      JsvObjectIterator it;
      jsvObjectIteratorNew(&it, function);

      JsVar *param = jsvObjectIteratorGetKey(&it);
      JsVar *value = jsvObjectIteratorGetValue(&it);
      while (jsvIsFunctionParameter(param) && value) {
        jsvAddFunctionParameter(functionRoot, jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH), value);
        jsvUnLock2(value, param);
        jsvObjectIteratorNext(&it);
        param = jsvObjectIteratorGetKey(&it);
        value = jsvObjectIteratorGetValue(&it);
      }
      jsvUnLock2(value, param);
      if (isParsing) {
        int hadParams = 0;
        // grab in all parameters. We go around this loop until we've run out
        // of named parameters AND we've parsed all the supplied arguments
        while (!JSP_SHOULDNT_PARSE && lex->tk!=')') {
          JsVar *param = jsvObjectIteratorGetKey(&it);
          bool paramDefined = jsvIsFunctionParameter(param);
          if (lex->tk!=')' || paramDefined) {
            hadParams++;
            JsVar *value = 0;
            // ONLY parse this if it was supplied, otherwise leave 0 (undefined)
            if (lex->tk!=')')
              value = jspeAssignmentExpression();
            // and if execute, copy it over
            value = jsvSkipNameAndUnLock(value);
            jsvAddFunctionParameter(functionRoot, paramDefined?jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH):0, value);
            jsvUnLock(value);
            if (lex->tk!=')') JSP_MATCH(',');
          }
          jsvUnLock(param);
          if (paramDefined) jsvObjectIteratorNext(&it);
        }
        JSP_MATCH(')');
      } else {  // and NOT isParsing
        int args = 0;
        while (args<argCount) {
          JsVar *param = jsvObjectIteratorGetKey(&it);
          bool paramDefined = jsvIsFunctionParameter(param);
          jsvAddFunctionParameter(functionRoot, paramDefined?jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH):0, argPtr[args]);
          args++;
          jsvUnLock(param);
          if (paramDefined) jsvObjectIteratorNext(&it);
        }
      }
      // Now go through what's left
      while (jsvObjectIteratorHasValue(&it)) {
        JsVar *param = jsvObjectIteratorGetKey(&it);
        if (jsvIsString(param)) {
          if (jsvIsStringEqual(param, JSPARSE_FUNCTION_SCOPE_NAME)) functionScope = jsvSkipName(param);
          else if (jsvIsStringEqual(param, JSPARSE_FUNCTION_CODE_NAME)) functionCode = jsvSkipName(param);
          else if (jsvIsStringEqual(param, JSPARSE_FUNCTION_NAME_NAME)) functionInternalName = jsvSkipName(param);
          else if (jsvIsStringEqual(param, JSPARSE_FUNCTION_THIS_NAME)) {
            jsvUnLock(thisVar);
            thisVar = jsvSkipName(param);
          }
#ifndef ESPR_NO_LINE_NUMBERS
          else if (jsvIsStringEqual(param, JSPARSE_FUNCTION_LINENUMBER_NAME)) functionLineNumber = (uint16_t)jsvGetIntegerAndUnLock(jsvSkipName(param));
#endif
          else if (jsvIsFunctionParameter(param)) {
            JsVar *defaultVal = jsvSkipName(param);
            jsvAddFunctionParameter(functionRoot, jsvNewFromStringVar(param,1,JSVAPPENDSTRINGVAR_MAXLENGTH), defaultVal);
            jsvUnLock(defaultVal);
          }
        }
        jsvUnLock(param);
        jsvObjectIteratorNext(&it);
      }
      jsvObjectIteratorFree(&it);

      // setup a the function's name (if a named function)
      if (functionInternalName) {
        JsVar *name = jsvMakeIntoVariableName(jsvNewFromStringVar(functionInternalName,0,JSVAPPENDSTRINGVAR_MAXLENGTH), function);
        jsvAddName(functionRoot, name);
        jsvUnLock2(name, functionInternalName);
      }

      if (!JSP_HAS_ERROR) {
        // save old scopes and reset scope list
        JsVar *oldScopeVar = execInfo.scopesVar;
        execInfo.scopesVar = 0;
        // if we have a scope var, load it up. We may not have one if there were no scopes apart from root
        if (functionScope) {
          jspeiLoadScopesFromVar(functionScope);
          jsvUnLock(functionScope);
        }
        // add the function's execute space to the symbol table so we can recurse
        if (jspeiAddScope(functionRoot)) {
          /* Adding scope may have failed - we may have descended too deep - so be sure
           * not to pull somebody else's scope off
           */

          JsVar *oldThisVar = execInfo.thisVar;
          if (thisVar)
            execInfo.thisVar = jsvRef(thisVar);
          else
            execInfo.thisVar = jsvRef(execInfo.root); // 'this' should always default to root


          /* we just want to execute the block, but something could
           * have messed up and left us with the wrong Lexer, so
           * we want to be careful here... */
          if (functionCode) {
#ifdef USE_DEBUGGER
            bool hadDebuggerNextLineOnly = false;

            if (execInfo.execute&EXEC_DEBUGGER_STEP_INTO) {
	      if (functionName)
		jsiConsolePrintf("Stepping into %v\n", functionName);
	      else
		jsiConsolePrintf("Stepping into function\n", functionName);
            } else {
              hadDebuggerNextLineOnly = execInfo.execute&EXEC_DEBUGGER_NEXT_LINE;
              if (hadDebuggerNextLineOnly)
                execInfo.execute &= (JsExecFlags)~EXEC_DEBUGGER_NEXT_LINE;
            }
#endif


            JsLex newLex;
            JsLex *oldLex = jslSetLex(&newLex);
            jslInit(functionCode);
#ifndef ESPR_NO_LINE_NUMBERS
            newLex.lineNumberOffset = functionLineNumber;
#endif
            JSP_SAVE_EXECUTE();
            // force execute without any previous state
#ifdef USE_DEBUGGER
            execInfo.execute = EXEC_YES | (execInfo.execute&(EXEC_CTRL_C_MASK|EXEC_ERROR_MASK|EXEC_DEBUGGER_NEXT_LINE));
#else
            execInfo.execute = EXEC_YES | (execInfo.execute&(EXEC_CTRL_C_MASK|EXEC_ERROR_MASK));
#endif
            if (jsvIsFunctionReturn(function)) {
              #ifdef USE_DEBUGGER
                // we didn't parse a statement so wouldn't trigger the debugger otherwise
                if (execInfo.execute&EXEC_DEBUGGER_NEXT_LINE && JSP_SHOULD_EXECUTE) {
                  lex->tokenLastStart = lex->tokenStart;
                  jsiDebuggerLoop();
                }
              #endif
              // implicit return - we just need an expression (optional)
              if (lex->tk != ';' && lex->tk != '}')
                returnVar = jsvSkipNameAndUnLock(jspeExpression());
            } else {
              // setup a return variable
              JsVar *returnVarName = jsvAddNamedChild(functionRoot, 0, JSPARSE_RETURN_VAR);
              // parse the whole block
              jspeBlockNoBrackets();
              /* get the real return var before we remove it from our function.
               * We can unlock below because returnVarName is still part of
               * functionRoot, so won't get freed. */
              returnVar = jsvSkipNameAndUnLock(returnVarName);
              if (returnVarName) // could have failed with out of memory
                jsvSetValueOfName(returnVarName, 0); // remove return value (which helps stops circular references)
            }
            // Store a stack trace if we had an error
            JsExecFlags hasError = execInfo.execute&EXEC_ERROR_MASK;
            JSP_RESTORE_EXECUTE(); // because return will probably have set execute to false

#ifdef USE_DEBUGGER
            bool calledDebugger = false;
            if (execInfo.execute & EXEC_DEBUGGER_MASK) {
              jsiConsolePrint("Value returned is =");
              jsfPrintJSON(returnVar, JSON_LIMIT | JSON_SOME_NEWLINES | JSON_PRETTY | JSON_SHOW_DEVICES);
              jsiConsolePrintChar('\n');
              if (execInfo.execute & EXEC_DEBUGGER_FINISH_FUNCTION) {
                calledDebugger = true;
                jsiDebuggerLoop();
              }
            }
            if (hadDebuggerNextLineOnly && !calledDebugger)
              execInfo.execute |= EXEC_DEBUGGER_NEXT_LINE;
#endif

            jslKill();
            jslSetLex(oldLex);

            if (hasError) {
              execInfo.execute |= hasError; // propogate error
              JsVar *stackTrace = jsvObjectGetChild(execInfo.hiddenRoot, JSPARSE_STACKTRACE_VAR, JSV_STRING_0);
              if (stackTrace) {
                jsvAppendPrintf(stackTrace, jsvIsString(functionName)?"in function %q called from ":
                    "in function called from ", functionName);
                if (lex) {
                  jspAppendStackTrace(stackTrace);
                } else
                  jsvAppendPrintf(stackTrace, "system\n");
                jsvUnLock(stackTrace);
              }
            }
          }

          /* Return to old 'this' var. No need to unlock as we never locked before */
          if (execInfo.thisVar) jsvUnRef(execInfo.thisVar);
          execInfo.thisVar = oldThisVar;

          jspeiRemoveScope();
        }

        // Unlock scopes and restore old ones
        jsvUnLock(execInfo.scopesVar);
        execInfo.scopesVar = oldScopeVar;
      }
      jsvUnLock(functionCode);
      jsvUnLock(functionRoot);
    }

    jsvUnLock(thisVar);

    return returnVar;
  } else if (isParsing) { // ---------------------------------- function, but not executing - just parse args and be done
    jspeParseFunctionCallBrackets();
    /* Do not return function, as it will be unlocked! */
    return 0;
  } else return 0;
}