[HN Gopher] Juice - Oberon JIT browser plugin (1996)
       ___________________________________________________________________
        
       Juice - Oberon JIT browser plugin (1996)
        
       Author : cylinder714
       Score  : 82 points
       Date   : 2024-02-02 08:48 UTC (14 hours ago)
        
 (HTM) web link (www.modulaware.com)
 (TXT) w3m dump (www.modulaware.com)
        
       | cylinder714 wrote:
       | Github: https://github.com/Spirit-of-Oberon/Juice
        
       | cornholio wrote:
       | > Juice's distribution format ... is based on a tree-shaped
       | program representation as is typically used transiently within
       | optimizing compilers. Rather than containing a linear code-
       | sequence that can be interpreted byte-by-byte, a Juice-encoded
       | applet contains a compressed tree that describes the actions of
       | the original program. The tree preserves the control-flow
       | structure of the original program, which makes it much easier to
       | perform code optimization while the tree is translated into the
       | native instruction set
       | 
       | Wow, that came out of the left field. Shipping a lexical compiler
       | IR and letting the target do the code generation sound like a
       | very powerful technique compared to compiling for virtual targets
       | like WASM, JVM etc. Wonder why it didn't caught on.
       | 
       | Another intriguing tidbit:
       | 
       | > By the very definition of our tree-encoding scheme, it is
       | impossible to encode a tree that violates scoping rules of our
       | source language. Such an "illegal" program cannot even be
       | constructed by hand.
        
         | ikari_pl wrote:
         | > Shipping a lexical compiler IR and letting the target do the
         | code generation sound like a very powerful technique compared
         | to compiling for virtual targets like WASM, JVM. Wonder why it
         | didn't catch on.
         | 
         | This is somewhat similar to what V8 does with JIT compilation
         | of javascript by now. I like the idea of doing it on AST rather
         | than direct (heavier) source code. But maybe in the long run,
         | gzipping the JS stream turned out to be just enough?
        
           | vidarh wrote:
           | Gzipping the JS stream is conceptually very different,
           | though. With Juice's approach, the intent is in part that the
           | compiler gets to do any amount of additional work before
           | serializing. What is shipped is already "half compiled", not
           | just serialized as a tree. It's closer to an intermediate
           | representation in tree form than just a representation of the
           | source syntax.
           | 
           | Today, with a lot of JS toolchains involving source-to-source
           | transformation first, _that_ could in theory achieve much of
           | the same potential of modifying the original input, and
           | lowering some things to a simpler subset etc., but just
           | compression isn 't the same.
           | 
           | The size reduction is pretty much a nice bonus with Juice
           | rather than the point - the dictionary encoding matters
           | because it means the decode gets similarity measures "for
           | free" and can generated patchable code segments for partial
           | subtrees that will be subsequently referenced.
        
         | vidarh wrote:
         | It's a direct continuation of Franz PhD thesis in '94 [1]. (I
         | note I know need to keep my URLs stable, as it turns out one of
         | the references to SDE in that Wikipedia article is my own
         | summary...).
         | 
         | I think there are two reasons it didn't catch on: The first
         | obviously being Java, and the sheer amount of mindshare Sun was
         | able to get for Java very quickly.
         | 
         | The other is that Oberon had gaps. It's a very austere
         | language. And while all of those gaps can be plugged - Franz
         | himself proposed extensions, as did other students of Wirth -
         | without someone putting in the effort to create an Oberon
         | version with sufficient expansions to appeal to business users,
         | the way Sun did with Java, that the underlying technology was
         | interesting didn't really matter.
         | 
         | I'm a big fan of the concept, but it's also more complex in
         | some ways, even though a crude implementation is also
         | potentially very simple. E.g. you "chop the compiler in two",
         | and unlike a bytecode compiler you get a tree to work on. At
         | the same time you can apply other JIT techniques - part of the
         | work on SDE meant reconstituting the dictionary used to
         | compress the tree on loading, and while doing so, if you
         | generate code during the process, you can also directly
         | reference the generated code to use as templates for a patching
         | JIT and insert those templates directly into the dictionary.
         | 
         | "One day" I hope to get time to explore SDE more, because it
         | seems JIT's have gotten so far down the bytecode path that
         | we're missing out on seeing what else might be viable.
         | 
         | Franz own later research shifted a lot towards Java, but his
         | students have interesting work in the JIT space too. Especially
         | Andreas Gal, and his work on trace trees.
         | 
         | [1] https://en.wikipedia.org/wiki/Semantic_dictionary_encoding
        
         | kgeist wrote:
         | Isn't it limiting? Say, the language evolves and its scoping
         | rules change, new control flow features are added etc. Now you
         | can't ship anything in the new version because of the old
         | clients. With bytecode, language implementers have more freedom
         | to change the language without having to force everyone to use
         | a new runtime version. I guess it's not a problem if the
         | language implementers also control the client (say, V8 in
         | Chrome) but in case of Juice, they were just another third-
         | party extension to Netscape, so overall it sounds like a bad
         | idea to me (if I understood it correctly that they serialized
         | and shipped AST to end users).
        
           | vidarh wrote:
           | You can read Franz' PhD dissertation on it here[1]. While
           | it's reasonable to describe it as serialising an AST, most of
           | the Oberon compilers of the time did not have an AST per se,
           | and so what you serialize is entirely arbitrary to your
           | choice of node types, and the operations used by the Oberon
           | version are low-level enough that while some work would have
           | needed to be done to be generic enough if one wanted to more
           | easily support other languages, it's largely moot. There's no
           | large semantic gap between what is serialized and the
           | generated code.
           | 
           | At that point it's no different from with Java - if you add
           | new bytecodes, the JVM needs to support it. Same here - if
           | you add new node types, the code generator will need to
           | support it.
           | 
           | Just as you wouldn't change the JVM bytecodes for every
           | language change, you likewise wouldn't _need_ to add new node
           | types to support most language changes for Juice either. You
           | could just as well choose to generate what in effect would be
           | an intermediate representation instead. You 'd only add new
           | node types if they provide a sufficiently big win over
           | generating more complex output, just as with the JVM
           | 
           | That said, nothing would've prevented dynamically updating
           | the code generator.
           | 
           | [1] https://oberoncore.ru/_media/library/franz_m.code-
           | generation...
        
         | nickpsecurity wrote:
         | It would also make client-side verification easier. You could
         | statically analyze code for safety before running it. You could
         | optimize it much further for your platform. Safe mashups might
         | be easier. Quite a few benefits to this.
         | 
         | One more is that, if you used an Oberon-based OS (eg A2
         | Bluebottle), the system and browser languages were the same. No
         | need to learn separate languages. Integration will be smoother,
         | too.
        
       | abricq wrote:
       | Interesting to see that Oberon-2 tried to go where Java
       | succeeded. I guess java worked better because of language
       | limitation. From my experiences in Oberon-2 (I work with it), I
       | find the following limitations enough to explain it.
       | 
       | - No generic types. That's really limiting. You want to implement
       | Linear Algebra for vectors ? You need a class for each possible
       | types.
       | 
       | - No proper error handling : no such thing as `TRY` or `CATCH`.
       | Instead, you need to pass a `BOOLEAN` mutable flag in functions
       | that may crash. That's just sad.
       | 
       | - No distinction between a class, an abstract class and
       | interfaces / pure abstract classes. If you want to write an
       | abstract class, you just `HALT` in the base methods (like you
       | would do in Python I guess). But there is no language semantic to
       | define that this class is abstract. So the compiler can't help
       | you out much with them.
       | 
       | - No enumerations. They are just very powerful.
       | 
       | (- Faulty garbage collector, even though that is not a a feature
       | of the language but rather of the implementation that I am
       | using.)
       | 
       | I am quite sure that Oberon was written with a real focus on
       | designing a language for which it is easy to write a compiler /
       | garbage collector. It really made sense back then. And they
       | succeeded in doing so. However, for broad distribution of
       | executable, it probably wasn't the best guess. These glimpses of
       | the past are so interesting though, discovery of the most optimal
       | tech stack was a long and dense path of exploration !
        
         | vidarh wrote:
         | There were proposals for mechanism for extending types from
         | several of Wirth's students, and Franz - one of the co-authors
         | of Juice - was one of the people who around that time wrote a
         | report on a proposal that'd enable runtime-loadable interface-
         | based extension, so all of this would certainly be fixable.
         | 
         | Juice also flows naturally from Franz PhD thesis, which was on
         | JIT compilation of Oberon from what in some sense was a
         | compressed serialized reduced form of the AST instead of
         | bytecode [I'll stress this is a gross oversimplification - his
         | compiler does do more processing, so I guess what is serialized
         | is closer to an IR in tree form than the AST]. I don't know how
         | much that changed in Juice, as I've never looked at it much but
         | from the description it remains at least similar in concept.
         | I've wished more work had gone into that ever since I read his
         | PhD thesis in '94.
        
           | pjmlp wrote:
           | It was used on Oberon System 3, and AOS.
           | 
           | When compiling you had the option to generate proper native
           | binaries, or slim ones to be JITed on load.
        
             | vidarh wrote:
             | Yeah, I'm aware it "stuck around" in the Oberon world, but
             | it's very annoying it hasn't escaped that niche, and hasn't
             | been iterated on more.
        
           | abricq wrote:
           | > Franz was one of the people who around that time wrote a
           | report on a proposal that'd enable runtime-loadable
           | interface-based extension
           | 
           | You seem to know a lot about this time. Would you have a
           | reference on this report ? I am quite curious now !
        
             | vidarh wrote:
             | On a phone and without a reference handy but search for
             | Franz and "Protocol Extension". It's a very short paper,
             | and basically proposed a mechanism similar to vtables, but
             | w/an extra level of indirection to allow whole interfaces
             | to be slotted in, and to have subsequent loaded
             | implementations addressed propagated down the class
             | hierarchy on load.
             | 
             | (I use a similar mechanism of propagating vtables updates
             | down the class hierarchy, but without the extra indirection
             | - at cost of more memory - in my prototype Ruby compiler)
        
               | abricq wrote:
               | Thank you, I got it: "Protocol extension, a technique for
               | structuring large extensible software systems" [0] !
               | Hoping to find time to read it soon, and also to look at
               | your ruby compiler !
               | 
               | [0]: https://www.research-
               | collection.ethz.ch/bitstream/handle/20....
        
               | vidarh wrote:
               | My Ruby compiler is, I'm sad to say, languishing. I got
               | it to a stage where it does compile itself successfully
               | (to 32 bit x86 assembly - 32 bit was still a reasonable
               | choice when I started...), but it has plenty of bugs (and
               | only compiles itself due to workarounds for those in the
               | compiler source to avoid triggering them) and doesn't
               | support most newer Ruby syntax, nor Regexp's or Float's
               | (other massively limitations too). I keep telling myself
               | I should at least fix the bugs at some point and strip
               | out the workarounds, but so many other projects at the
               | moment.
        
         | willvarfar wrote:
         | > my experiences in Oberon-2 (I work with it)
         | 
         | really interesting that you work with something as niche as
         | Oberon! :)
         | 
         | Can you talk about who is using Oberon, for what, and why?
        
           | abricq wrote:
           | About the what, I can't tell you too much unfortunately. We
           | do realtime OS for autonomous robots in Oberon. About the
           | why, it's a question of heritage from the past. The code
           | works, so why taking the risk to migrate it. It's really a
           | big code base, so migrating it would be (will be...) very
           | risky for all of our running platforms.
        
             | Rochus wrote:
             | That's amazing. Which compiler are you using?
        
               | abricq wrote:
               | In-house compiler, specifically made for the architecture
               | that we sell, we have to maintain it but we rarely touch
               | it. I am quite sure that it was related to System3, I
               | know that we used to use System3 in the past. But this
               | part I am not sure, as I am quite young and I personally
               | never worked with it. Unfortunately it's not open-source,
               | but it's just a standard compiler pretty much without
               | optimization. In our case, it's the responsibility of the
               | developer to write optimal code, since our compiler does
               | help. I'd be curious to chat about your version of
               | embedded Oberon, I will write to you !
        
           | Davidbrcz wrote:
           | Bluebotics, in Switzerland, has its whole embedded box
           | written in Oberon.
           | 
           | Cool product, terrible boomer management.
        
             | pjmlp wrote:
             | I wasn't aware of them, most likely same path as Oberon
             | microsystems which ended up creating Component Pascal, I
             | was quite fond of, unfortunely didn't survive against Java
             | and .NET.
             | 
             | Nowadays Oberon microsystems business has nothing to do
             | with Oberon.
        
               | Davidbrcz wrote:
               | I can assure you that company's Oberon code base is alive
               | and will outlive COBOL.
        
         | pjmlp wrote:
         | As proven by Go, those limitation don't matter when the
         | language has an overlord to push it.
         | 
         | I was a big Oberon fan[0], not so much for Go, because in
         | mid-90's using Native Oberon was an eye opening experience, in
         | the hardware we had available back then.
         | 
         | 20 years later (at Go 1.0 time), not so much.
         | 
         | [0] - The whole linage, and still think Active Oberon is the
         | best dialect (with AOS) that eventually came to be, after
         | Oberon v1.0 from 1987.
        
           | wirrbel wrote:
           | To me Go seems like almost a copycat of Oberon with channels
           | added. But I neither used Oberon nor Go so that's more of a
           | spec-reading impression. What would you say having used both?
        
             | pjmlp wrote:
             | It is more like a Limbo copy cat, with a bit of Oberon
             | influences.
             | 
             | As strange as it may sound, UNIX folks were Oberon fans,
             | hence why ACME in Plan 9 had a similar developer workflow
             | as the whole Oberon UI, where clickable text is combined
             | with dynamic UI actions.
             | 
             | Plan 9 failed short of using a userspace systems language
             | as C's successor (see Alef[0]).
             | 
             | Plan 9's sucessor, Inferno, fixed this with Limbo [1],
             | where C is only used for the kernel, disVM, and a couple of
             | userspace libraries, everything else done in Limbo.
             | 
             | Go ends up being a mix of Limbo, Oberon-2 method syntax and
             | SYSTEM package.
             | 
             | However one thing that both Limbo and Oberon based systems
             | have, and Go misses out, in how the whole platform embraces
             | dynamic linking to extend existing applications, and
             | surface operations to the UI.
             | 
             | By the way, I advise wasting a couple of hours diving into
             | Inferno and Limbo's manuals[2],
             | 
             | [0] -
             | https://en.wikipedia.org/wiki/Alef_(programming_language)
             | 
             | [1] - https://www.vitanuova.com/inferno/limbo.html
             | 
             | [2] - https://www.vitanuova.com/inferno/docs.html
        
         | mypalmike wrote:
         | To be fair, Java didn't have generic types when Juice was
         | announced.
        
           | jbverschoor wrote:
           | Nor enums.
           | 
           | The thing that made Java great were conventions (file per
           | class etc) and its standard library (esp collections)
           | 
           | Unsurprisingly, that is exactly what made Ruby great
        
         | Rochus wrote:
         | > _No generic types .. No proper error handling .. No
         | enumerations_
         | 
         | Have a look at this version of Oberon which has generic
         | modules, exceptions, enumerations and much more:
         | https://oberon-lang.github.io/
         | 
         | Also a concurrency concept is work in progress:
         | https://github.com/oberon-lang/oberon-lang.github.io/blob/ma...
        
           | abricq wrote:
           | Every now and then I look at this site, I hope the project
           | keeps growing !
        
             | Rochus wrote:
             | Since your project is apparently about robots, how do you
             | handle concurrency with Oberon? Or how can you avoid it? In
             | case you're willing to share experience, you can contact me
             | on me@rochus-keller.ch. (Btw: I'm currently working on a
             | low-level version of Oberon without GC which can be used as
             | C substitute.)
        
         | andai wrote:
         | I thought exceptions were considered harmful in current year.
         | (Opinions may differ.)
         | 
         | Also the abstract class thing didn't stop C++, lol
        
           | abricq wrote:
           | I'm curious if you have some references about this, if you
           | have read good blog posts or something ! I can think of Rust
           | that does not have exception, but it's not because they
           | didn't address the problem of error handling: exception are
           | replaced by `Result`, if I'm not wrong. In Oberon there's
           | simply no error handling mechanism.
        
             | eterps wrote:
             | There's nothing preventing you to use a Result type in
             | Oberon. Just not as a fancy algebraic data type, but rather
             | as a regular record/struct type.
        
         | cmrdporcupine wrote:
         | Can you really say Java succeeded in that sphere? It's simply
         | not the case that Java applets had success. I was an early
         | adopter, and was even paid to write a couple Java applets in
         | '97, but I would say the whole thing was... questionable. They
         | lingered about for a few years being badly supported and having
         | a not-great security story, and then were unceremoniously
         | killed.
         | 
         | The potential was there, but in reality people just used Flash,
         | and when the DOM/JavaScript interface became more competent,
         | they switched to using JS.
         | 
         | And, yeah, as others pointed out... Java did not have generics,
         | or enums until 1.4, and its exception mechanism hasn't really
         | stood the test of time.
        
           | pjmlp wrote:
           | Every time I have to track down exceptions in production on
           | .NET projects, I deeply miss checked exceptions, because
           | _some_ people just code away without caring one second to
           | check their errors.
        
             | cmrdporcupine wrote:
             | When I worked in Java (11+ years ago) the style dogma was
             | to never use checked exceptions.
        
               | pjmlp wrote:
               | That won't fly in code review in most Java shops I worked
               | on.
               | 
               | Also the way modern languages that are worshiped for
               | forcing to handle return values, with pattern matching,
               | try and ? operators, it is nothing other than proving the
               | point checked exceptions matter, even if they come with a
               | different flavour.
        
               | cmrdporcupine wrote:
               | Good to hear. I used to get scolded for using checked
               | exceptions.
               | 
               | But it was the 2010s.
               | 
               | These days I work in languages with better static
               | guarantees. Always wanted that back then, but felt like a
               | minority.
        
               | pjmlp wrote:
               | I have been doing Java projects since 2006, and as
               | mentioned on my edit you might have missed when replying,
               | pattern matching, try and ? are just another way to
               | package checked exceptions in a different coating.
        
               | cmrdporcupine wrote:
               | Yes and no. There's a non-local-control aspect to
               | exceptions that's a bit different from explicit return or
               | ? in that it's explicit in the text of the program rather
               | than in the signature of the method. But yes, the
               | compiler will stop you in either case, so that's fine.
               | 
               | But there's no guarantee that someone under you didn't go
               | and pull out a RuntimeException on you.
        
       | syrusakbary wrote:
       | So Juice was the WebAssembly from the Netscape era?
        
         | blackoil wrote:
         | No, it was an Applet from Java era.
        
           | pjmlp wrote:
           | Which nowadays you can replicate on top of WebAssembly.
           | 
           | https://chromewebstore.google.com/detail/cheerpj-applet-
           | runn...
        
         | FullyFunctional wrote:
         | WASM uses a block structured IR (that is, no arbitrary gotos)
         | and I would characterize it as in between of the [serialized]
         | Juice AST and the flat Java bytecodes.
         | 
         | From the compiler's point of view the Juice AST is the same as
         | source code so I'd expect the Juice JIT to have slight more
         | code generation flexibility than the type-erased WASM.
        
       | cybervegan wrote:
       | I actually used that a bit at the time, but it the web was too
       | young and browsers and HTML were too immature to support it well.
        
       | basementcat wrote:
       | I installed the Juice browser plug-in back then and remembered
       | how Juice applets "loaded" much faster than their equivalent Java
       | counterparts. Once loaded, Juice and Java applet performance was
       | similar. Over time, Java benefited from a larger network effect
       | and market share and I stopped seeing Juice applets on the web.
        
         | eterps wrote:
         | I remember that difference as well. It's a shame it didn't take
         | off.
        
       ___________________________________________________________________
       (page generated 2024-02-02 23:01 UTC)