Interpreter: Disallow recursion

I think this is the minimum rule that's easy to understand when writing
SkSL for the interpreter that ensures we'll be able to statically
determine total stack usage of a particular function.

While writing the new test, I also noticed that we still return
(invalid) byte code, even when there are errors. Fixed that.

Change-Id: I625a8592c9ba1656074e5f0d4227d41968af7b37
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/226218
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp
index e86dd86..5a8030a 100644
--- a/src/sksl/SkSLByteCodeGenerator.cpp
+++ b/src/sksl/SkSLByteCodeGenerator.cpp
@@ -81,12 +81,7 @@
                 ; // ignore
         }
     }
-    for (auto& call : fCallTargets) {
-        if (!call.set()) {
-            return false;
-        }
-    }
-    return true;
+    return 0 == fErrors.errorCount();
 }
 
 std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const FunctionDefinition& f) {
@@ -669,7 +664,23 @@
         return;
     }
 
-    // Otherwise, we may need to deal with out parameters, so the sequence is trickier...
+    // Find the index of the function we're calling. We explicitly do not allow calls to functions
+    // before they're defined. This is an easy-to-understand rule that prevents recursion.
+    size_t idx;
+    for (idx = 0; idx < fFunctions.size(); ++idx) {
+        if (f.fFunction.matches(fFunctions[idx]->fDeclaration)) {
+            break;
+        }
+    }
+    if (idx > 255) {
+        fErrors.error(f.fOffset, "Function count limit exceeded");
+        return;
+    } else if (idx >= fFunctions.size()) {
+        fErrors.error(f.fOffset, "Call to undefined function");
+        return;
+    }
+
+    // We may need to deal with out parameters, so the sequence is tricky
     if (int returnCount = SlotCount(f.fType)) {
         this->write(ByteCodeInstruction::kReserve);
         this->write8(returnCount);
@@ -689,7 +700,7 @@
     }
 
     this->write(ByteCodeInstruction::kCall);
-    fCallTargets.emplace_back(this, f.fFunction);
+    this->write8(idx);
 
     // After the called function returns, the stack will still contain our arguments. We have to
     // pop them (storing any out parameters back to their lvalues as we go). We glob together slot