Define own structures/classes (assembly only?)
GotoFinal
Would be useful to be able to define own structures of data, especially if support of collections like lists would be added ( https://feedback.vrchat.com/vrchat-udon-closed-alpha-feedback/p/add-major-c-collection-types ), as then it would be very useful to have single variable that can store some structure of data.
Log In
Momo the Monster
Merged in a post:
Support types and functions on Udon VM Natively
Ram․Type-0
In past, I saw that custom type system are not included in Udon,but we can implement types in our custom Udon compiler.
We can implement custom value type(It means struct in C#) by expanding it member variables recursively.
But it seems that we cannot implement reference types(It means class in C#) on Udon VM.
It because Udon VM lacks dynamic allocation operations,and referencing system.
When we want to implement "new" operations, new object must have it own field variables.
But in UdonVM, we could only allocate variables statically.(by define it address statically).
And dynamic address assignments are not supported in Udon VM instruction set,we could not manage reference.
Please support types natively.
Jon~
this would have to be done in a language that is compiled down to the assembly, classes and structs are mostly a language-based thing and aren't really supposed to be a feature in assembly, I'd say wait for a compiler for a language that has structs n classes
GotoFinal
Jon~: it can be done by language but performance and interoperability would take a great hit, with support from bytecode level (just how c#/java bytecode have it) you could later combine many scripts from different compilers and still be able to exchange objects between them. And performance of existing data structures in c# will be just much better than the one made in interpreted bytecode.
JakEne
Jon~: I agree, RISC > CISC. What we really need are load and store operations for structure and array creation on the heap. https://feedback.vrchat.com/vrchat-udon-closed-alpha-feedback/p/load-and-store-operations
GotoFinal
JakEne: But this isn't raw assembly, we don't have access to memory or anything like that. to create structures you would need to generate shit tons of global variables, and is interpreted language so RISC is only hurting performance as less operations can be performed on native compiled side, and more must be interpreted.
Additionally in future it would be nice to be able to make calls cross-scripts, and with support for objects at language level we could exchange objects between scripts made with different compiler without worring about compatibility between them.
JakEne
GotoFinal: Excuse me, what? The whole point of having the UdonVM ops to handle this is so that they are optimized by the AOT compiler. That is incredibly easy for the compiler to do with all RISC ops by design of RISC architecture. The ability for deep optimizations is literally the primary motivation behind RISC (and one of many reasons it's often so power efficient in hardware). It is not, however, possible for good optimizations to occur with CISC ops as you are suggesting get added.
GotoFinal
JakEne: UdomVM is an interpreter, there are no further optimization done to udon bytecode. It's simple vm that iterate over opcodes on big switch with 10 possible bytecodes, including 2 noop bytecodes. And I don't ever expect to see any from vrchat team. So we will either get more opcodes, just like we have in other bytecode interpreted languages like java/c# (skipping the jit part that probably will never exit for udon) or we will have mess with shit tons of pre-declared global variables (and number of them is limited in VM to some constant) and no way to have common code that can be shared across different languages working on udonvm.
I don't know where you got the idea of AOT compilation for udon?
JakEne
GotoFinal: We are not talking about programs running in the UdonVM. I'm not sure where you got that idea. AOT is used to compile UdonVM and every op they add to it. Adding ops with inputs and outputs that are indeterminate at compile time (ie, what you're asking for with this feedback) will prevent AOT from performing many optimizations.
JakEne
GotoFinal:
"RISC is only hurting performance as less operations can be performed on native compiled side, and more must be interpreted."
I don't think you quite understand what RISC even means. How could
ADD, output, arg1, arg2
that would run directly without needing function call through the interpreter be slower than 3 heap ops and a function call op PUSH, arg1\n PUSH, arg2\n PUSH, output\n EXTERN, "SystemPrimitive.__op_Addition__SystemPrimitive_SystemPrimitive__SystemPrimitive
?GotoFinal
JakEne: AOT already can't perform any advanced optimizations here, as it is used for dynamic scrips, so there isn't much to optimize. My proposed features don't need to be more "indeterminate" than existing opcodes, as could be implemented in similar/same way as current heap is implemented.
GotoFinal
JakEne: like with your exact example: udon does not have ADD operation, it can only execute externs, it does not have any instructions to operate on data. There is no "add" opcode. Everything is an extern. So yea, would also be nice to have more opcodes like ADD one too. Currently you can only load variables and execute externs.
JakEne
GotoFinal: That operation and other arithmetic, logic, and basic memory ops is what fundamental RISC is. I'm talking about optimizations within the UdonVM itself, not what the UdonVM runs. Any ops added to the vm should be highly optimizable, which is why I don't think any op should be handling structures that can't be determined when the UdonVM is compiled by the vrchat team.
JakEne
GotoFinal: Heap manipulation ops (load and store) would allow people creating compilers to choose how to create their own structures in memory and optimize based on the program being compiled. Removing the burden on the vrchat devs to create a complex assembler that attempts to handle the optimizations without knowledge of the program source being compiled.
GotoFinal
JakEne: just like heap content can't be determined when UdonVM is compiled, so in same way any current opcode, as all of them operate on this heap, it does not change anything here. So additional opcoded could be written in optimized form to perform some tasks, as AOT can't optimize our scripts more, but additional more specialized opcodes can.
Like in same way performance of string replace written on raw opcodes to iterate over chars of string on udonvm would be just horrible compared to single call to existing function in C# that was already optimized by AOT.
GotoFinal
JakEne:
> creating compilers to choose how to create their own structures in memory
But we don't have access to memory, and each access is already costly due to additional scans and walls of ifs for each read and write.
So when creating a compiler you can't really choose too much, as you are already limited by the VM. And lack of access to actual memory for sure will not change, so its better to get some more specialized operations.
JakEne
GotoFinal: Not quite. AOT cannot know the properties of that string and it is therefore not possible to optimize. However a compiler building directly for UdonVM and operating on a char array directly in udon heap would be able to determine what optimization if any to perform. The RISC ops such a compiler would use in the UdonVM would be so simple that AOT can actually optimize them very close to the hardware ops they represent.
JakEne
GotoFinal: A constant predetermined heap size would make performance a non-issue
GotoFinal
JakEne:
> AOT cannot know the properties of that string and it is therefore not possible to optimize.
But it does not need to, c# string replace method will be already optimized by AOT, not for every possible string, but it will be simple machine code to perform an replace of string.
Where the version wrote on UdonVM using some compiler will still need to iterate on all opcodes, go thro a lot of branches on each heap read/write (and this will be performed for each char in string).
There is just no way for interpreted code to run here faster than native one, its a big and complex operation with a lot of reads and writes for udon.
Expect for cases where compiler could just get rid of some replace function as result would be known at compile time, but thats an edge case that I would not expect to happen. As in most cases it will be dynamic string replaced by dynamic string, something that you can't optimize more than just replace logic itself.