Starlight is a JS engine in Rust which focuses on performance rather than ensuring 100% safety of JS runtime.

Overview

starlight

Starlight is a JS engine in Rust which focuses on performance rather than ensuring 100% safety of JS runtime.

Features

  • Bytecode interpreter
  • GC
  • Polymorphic inline caches for objects and variable lookups

Why?

I was developing my own JS-like language but then I realized that there's no point in it and decided to try to create optimized JS engine with JIT,inline caches, fast GC and other fun stuff that is interesting me.

Starlight VS Boa

Starlight is much faster than Boa in a lot of ways one of which is object property accesses but Starlight is designed more like JS engine that can be potentionally used in web browsers like V8 and JSC and not something small and embedabble (we have 1.6MB binary through!).

TODO

  • Complete support for full ES5.1 and some part of ES6 (we already support spread,const and let).
  • Advanced conservative on stack garbage collector (no more reference counted roots yay!)
  • JIT compiler
  • Benchmarks against SpiderMonkey without JIT
Comments
  • WIP: feat: add realm

    WIP: feat: add realm

    TODO

    • [x] CreateRealm, SetDefaultGlobalBindings
    • [ ] CreateIntrinsics, first create intrinsics, then constrcut global object using intrinsics
    • [ ] use realm to run test262
    opened by jameslahm 15
  • eval requires return statement

    eval requires return statement

    Hi,

    I'm building a wrapper for starlight just like my quickjs project and i'm bumping into some issues.

    When running Runtime.eval() with:

    (1 + 1)
    

    i get a JsValue with type_of() undefined.

    When i run:

    return (1 + 1);
    

    i do get a JsValue with type_of(): number.

    eval should not require a return statement

    full example:

    use starlight::vm::{RuntimeParams, GcParams};
    use starlight::Platform;
    
    fn main(){
        let options = RuntimeParams::default();
        let gc_params = GcParams::default();
        let mut sl_rt = Platform::new_runtime(options, gc_params, None);
        let script = "(1 + 1);";
        let val = sl_rt.eval(None, true, script, true).ok().expect("script failed");
        println!("typeof = {}", val.type_of());
        // does not work // assert!(val.is_int32());
        let script = "return (1 + 1);";
        let val = sl_rt.eval(None, true, script, true).ok().expect("script failed");
        println!("typeof = {}", val.type_of());
        assert!(val.is_int32());
    }
    
    opened by andrieshiemstra 15
  • async/promise PoC

    async/promise PoC

    This is more a review request than a final PR

    • questions
      • [ ] for persistent roots i use a HashMap based on a generated ID, at first i thought i'd just use the inner ptr of JsObejct as ID but then it would not work when multiple jobs add a persistent root for the same object. I once implemented an AutoIdMap for use case like this but it's far from perfect. does anyone know a more std/elegant solution for things like this?
      • [x] For persistentRoots i'dd like to create a strcut which releases the root on Drop but i need a ref to the Runtime, (or at leasts it's map of roots) should i just add an Rc to the map or is there allready a way to have some sort of reference to the Runtime?
    • todos
      • [ ] static Promise methods like .all
      • [ ] test cases
      • [x] if resolved or rejected with sub Promise, reject or resolve with result of sub promise
      • [x] constructor, run executor sync, in resolve run subs async
    opened by andrieshiemstra 6
  • how does async work / how is async going to work in starlight

    how does async work / how is async going to work in starlight

    Based on what you said in #44 i had a look at function.rs and generator.rs and i don't quite understand how that is going to work async

    JavaScript engines typically rely on running in an EventLoop and provide a way to expose jobs which should be added to that loop.

    QuickJS has an internal vec of pending jobs accessed by calling JS_IsJobPending() and then JS_ExecutePendingJob() (the downside of this is that you have call those after everything you do with the quickjs runtime).

    Spidermonkey has a more elegant solution, you can add a hook (fn/closure) for when an async job has to run (SetJobQueue())

    For quickjs I implemented an generic EventLoop here: https://github.com/HiRoFa/utils/blob/master/src/eventloop.rs

    For Promises in starlight i was planning to add a simple hook (vm.registerJobAddHookThingy(Fn(Job)) which in turn adds the job to the EventLoop so it wil run async (but in the same thread) but i'm wondering if that's the way you want to go or have an other solution for async jobs...?

    opened by andrieshiemstra 5
  • Implement Context

    Implement Context

    Now the realm api is very simple

    let rt = Runtime::new(...)
    let ctx1 = Context::new(rt)
    let ctx2 = Context::new(rt)
    // ctx1 and ctx2 are standalone realm, not influence each other
    ctx1.eval()
    ctx2.eval()
    

    TODO

    • [x] serialize and deserialize
    • [x] allocate context on heap
    opened by jameslahm 3
  • Question about functions

    Question about functions

    Hi,

    I'm working on creating callbacks (JsFunctions from Fn closures) from rust.

    With quickjs and spidermonkey i register those in a map with a anique id and then create a function with some metadata

    In quickjs there is JS_NewCFunctionData which calls a function with a data JSObject. In spidermonkey i just add a variable to the Function object which is passed to the native function (like as arguments.callee)

    Currently with starlight i'd have to bind the function to a second JsValue so i can access the metadata JsValue as this.

    All three methods work, but are cumbersome.

    Would it be ok if i added a fifth option to functions::FuncType something like this?

    Closure<JsClosureFunction>
    
    struct JsClosureFunction {
        pub(crate) closure: Fn(&mut Runtime, arguments: &Arguments) -> Result<JsValue, JsValue>
    }
    

    Or do you have an other suggestion?

    enhancement 
    opened by andrieshiemstra 3
  • Windows segfaults

    Windows segfaults

    Since 6d4a40bae14bd18341063c927bc9aa0cd044a891 windows CI build segfaults when test262 is running. I do not have Windows machine and can't investigate in this issue

    cc @jameslahm

    opened by playXE 2
  • Any differences with Deno?

    Any differences with Deno?

    As Deno is covering TypeScript/ES6 and also written in Rust, is there any major design differences between starlight and Deno?

    Any particular design goal that makes this JS engine different?

    opened by schungx 2
  • holyjit

    holyjit

    https://github.com/nbp/holyjit

    The project is dead but you could get some inspiration there. The idea is that you only write interpreter and some wodoo macro will eventually generate very efficient code for that interpreter. But it doesn't have to be interpreted anymore. A bit like JIT JIT compiler.

    It's super ambitious but it has been done already - GraalVM compiler is the most successful and production-ready example. TBH, they have far more resources but they also have much bigger scope, so... Definitely possible.

    It might be easier to resurrect the project and use it instead of doing JIT all by yourself (and it might be for other dynamic languages implemented in rust).

    I would do that myself if I was not busy with other things in my life right now (yeah, I know)

    opened by cztomsik 2
  • Rewrite of VM execution pipeline

    Rewrite of VM execution pipeline

    I decided to go JSC way with register based bytecode i.e stack allocated call frames, vPC and other fun stuff that it has. This PR will not be merged soon as there's still lots of work to do.

    opened by playXE 1
  • Lazy compilation (replacement to snapshots)

    Lazy compilation (replacement to snapshots)

    Snapshots are cool but they tend to consume some heap memory and require a fully initialized heap. When we will switch to Comet as our GC we should replace snapshots with lazy init.

    Pros:

    • Same fast startup time
    • Less memory consumption. Memory is allocated on demand
    • Simplify code base. Snapshots require a lot of maintenance and it is quite hard to debug them.

    Cons:

    • No way to create a fully initialized VM instance on the fly
    enhancement 
    opened by playXE 0
  • Register based bytecode

    Register based bytecode

    Stack based bytecode is quite hard to maintain especially when you have to deal with iterators so I want to get register based bytecode in Starlight. We could write a DSL for generating one just like JSC: https://github.com/WebKit/WebKit/blob/main/Source/JavaScriptCore/bytecode/BytecodeList.rb https://github.com/WebKit/WebKit/tree/main/Source/JavaScriptCore/generator

    opened by playXE 1
  • New calling convention

    New calling convention

    We need faster and easier to use calling convention. For this purpose we have to know function stack size ahead of time (done in 0f5d078e1399c7ef41e45ecb298fcffd57d4571c) and allocate memory on the stack (alloca-rs will be used). This way we get faster calls and easier JIT in the future.

    Also I thought about precalculating catch stack size which will remove all the heap allocation that happens right now during call to JS.

    enhancement 
    opened by playXE 0
  • Variables broken

    Variables broken

    let x = 0;
    function f() {
      let x = 1;
      g();
      print(x);
    }
    
    function g() {
      print(x);
      x = 2;
    }
    
    
    Code block 'f' at 0x7f4e715d3718: 
     is strict?=false
    0000: push_int <1>
    0005: decl_let 0
    0010: push_undefined
    0011: get_environment 1
    0016: get_local 1
    0021: call <0>
    0026: pop
    0027: push_undefined
    0028: global_object
    0029: try_get_by_id 0, fdbk 0
    0038: get_environment 0->get_local 0
    0043: call <1>
    0048: pop
    0049: push_undefined
    0050: ret
    
    Code block 'g' at 0x7f4e715d35d8: 
     is strict?=false
    0000: push_undefined
    0001: global_object
    0002: try_get_by_id 0, fdbk 0 // this is lookup for `x` but it should just use get_environment 1 -> get_local
    0011: global_object
    0012: try_get_by_id 1, fdbk 1
    0021: call <1>
    0026: pop
    0027: push_int <2>
    0032: global_object
    0033: put_by_id 1, fdbk 2
    0042: push_undefined
    0043: ret
    
    Code block '<script>' at 0x7f4e715d3858: 
     is strict?=false
    0000: get_function 0
    0005: get_environment 0->set_local 2
    0010: get_function 1
    0015: get_environment 0->set_local 1
    0020: push_int <0>
    0025: decl_let 3
    0030: push_undefined
    0031: ret
    
    bug 
    opened by playXE 1
  • Try Catch Finally

    Try Catch Finally

    This issue was used to track all problems about the try-catch finally statement problem.

    Known Issues: #7 Pr: #60

    Known Problems:

    • throw in catch clause
    try {
    } catch {
      throw 123;
    } finally {
    }
    
    • throw in a inner function
    try {
    } catch {
      ThrowErrorFunc()
    } finally {
    }
    
    • return in try clause
    try {
     return 1
    } catch {
    } finally {
    }
    
    • return in catch clause
    try {
    } catch {
      return 1
    } finally {
    }
    
    opened by jameslahm 0
Owner
null
Sōzu HTTP reverse proxy, configurable at runtime, fast and safe, built in Rust. It is awesome! Ping us on gitter to know more

Sōzu · Sōzu is a lightweight, fast, always-up reverse proxy server. Why use Sōzu? Hot configurable: Sozu can receive configuration changes at runtime

sōzu 2k Dec 30, 2022
Rust Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.

Rust Embed Rust Custom Derive Macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev. Y

Peter 1k Jan 5, 2023
A Rust application which funnels external webhook event data to an Urbit chat.

Urbit Webhook Funnel This is a simple Rust application which funnels external webhook event data to an Urbit chat. This application is intended to be

Robert Kornacki 15 Jan 2, 2022
Super Fast & High Performance minimalist web framework for rust

Super Fast & High Performance minimalist web framework for rust

null 6 Oct 12, 2022
Noria: data-flow for high-performance web applications

Noria: data-flow for high-performance web applications Noria is a new streaming data-flow system designed to act as a fast storage backend for read-he

MIT PDOS 4.5k Dec 28, 2022
Oso is an open source policy engine for authorization that’s embedded in your application

Oso What is Oso? Oso is an open source policy engine for authorization that’s embedded in your application. It provides a declarative policy language

oso 2.8k Jan 4, 2023
A Google-like web search engine that provides the user with the most relevant websites in accordance to his/her query, using crawled and indexed textual data and PageRank.

Mini Google Course project for the Architecture of Computer Systems course. Overview: Architecture: We are working on multiple components of the web c

Max 11 Aug 10, 2022
Layers, extractors and template engine wrappers for axum based Web MVC applications

axum-template Layers, extractors and template engine wrappers for axum based Web MVC applications Getting started Cargo.toml [dependencies] axum-templ

Altair Bueno 11 Dec 15, 2022
A fast GraphQL engine.

bluejay-rb Warning This project is still very early in its development and should be considered highly unstable and experimental. It is incomplete and

Adam Petro 4 Feb 20, 2023
Rust I18n is use Rust codegen for load YAML file storage translations on compile time, and give you a t! macro for simply get translation texts.

Rust I18n Rust I18n is use Rust codegen for load YAML file storage translations on compile time, and give you a t! macro for simply get translation te

Longbridge 73 Dec 27, 2022
lispr is a Rust macro that tries to implement a small subset of LISPs syntax in Rust

lispr lispr is a Rust macro that tries to implement a small subset of LISPs syntax in Rust. It is neither especially beautiful or efficient since it i

Jan Vaorin 0 Feb 4, 2022
Rust/Axum server implementation with PCR(Prisma Client Rust)

Realworld Rust Axum Prisma This project utilizes Rust with the Axum v0.7 framework along with the Prisma Client Rust to build a realworld application.

Neo 3 Dec 9, 2023
A Rust web framework

cargonauts - a Rust web framework Documentation cargonauts is a Rust web framework intended for building maintainable, well-factored web apps. This pr

null 179 Dec 25, 2022
A Rust library to extract useful data from HTML documents, suitable for web scraping.

select.rs A library to extract useful data from HTML documents, suitable for web scraping. NOTE: The following example only works in the upcoming rele

Utkarsh Kukreti 829 Dec 28, 2022
openapi schema serialization for rust

open api Rust crate for serializing and deserializing open api documents Documentation install add the following to your Cargo.toml file [dependencies

Doug Tangren 107 Dec 6, 2022
📮 An elegant Telegram bots framework for Rust

teloxide A full-featured framework that empowers you to easily build Telegram bots using the async/.await syntax in Rust. It handles all the difficult

teloxide 1.6k Jan 3, 2023
A html document syntax and operation library written in Rust, use APIs similar to jQuery.

Visdom A server-side html document syntax and operation library written in Rust, it uses apis similar to jQuery, left off the parts thoes only worked

轩子 80 Dec 21, 2022
Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.

Actix 16.2k Jan 2, 2023
A web framework for Rust.

Rocket Rocket is an async web framework for Rust with a focus on usability, security, extensibility, and speed. #[macro_use] extern crate rocket; #[g

Sergio Benitez 19.4k Jan 4, 2023