Giter Site home page Giter Site logo

eosio / eos-vm Goto Github PK

View Code? Open in Web Editor NEW
195.0 37.0 60.0 3.47 MB

A Low-Latency, High Performance and Extensible WebAssembly Backend Library

License: Other

CMake 0.39% C++ 98.54% Python 0.05% Shell 0.11% Dockerfile 0.24% Makefile 0.01% JavaScript 0.48% WebAssembly 0.17%

eos-vm's Introduction

EOS VM - A Low-Latency, High Performance and Extensible WebAssembly Engine

  • Extremely Fast Execution
  • Extremely Fast Parsing/Loading
  • Efficient Time Bound Execution
  • Deterministic Execution (Soft Float & Hardware Floating Point options)
  • Standards Compliant
  • Designed for Parallel Execution
  • C++ / Header Only
  • Simple API for integrating Native Calls

Motivation

EOS VM is designed from the ground up for the high demands of blockchain applications which require far more from a WebAssembly engine than those designed for web browsers or standards development. In the world of blockchain, any non-deterministic behavior, unbounded computation, or unbounded use of RAM can take down the blockchain for everyone, not just a single user's web browser. Single threaded performance, fast compilation/validation of Wasm, and low-overhead calls to native code are critical to blockchains.

While EOS VM was designed for blockchain, we believe it is ideally suited for any application looking to embed a High Performance WebAssembly engine.

We designed EOS VM to meet the needs of EOSIO blockchains after using three of the most common WebAssembly engines: Binaryen, WABT, and WAVM. These WebAssembly engines were the single largest source of security issues impacting EOSIO blockchains. While WAVM provides extremely fast execution, it is not suited to running a live blockchain because it has extremely long and unpredictable compilation times and the need to recompile all contracts every time the process restarts. WABT was designed as a toolkit for manipulating WebAssembly first and as an execution engine second.

We considered the WebAssembly engines used by the largest browsers, but they all come with considerable overhead and assumptions which are inappropriate for a reusable library or to be embedded in a blockchain. It is our hope that one day major browsers will opt to switch to EOS VM.

All of the existing libraries incorporate a large code base designed and implemented by engineers not trained in the rigor of blockchain development. This makes the code difficult to audit and keeping up with upstream changes / security breaches difficult.

With WebAssembly (Wasm) becoming ever more ubiquitous, there is a greater need for a succinct implementation of a Wasm backend. We implemented EOS VM because all existing backends we evaluated fell short in meeting our needs for a Wasm backend best suited for use in a public blockchain environment.

Deterministic Execution

Given that all programs on the blockchain must be deterministic, floating point operations are of particular interest to us. Because of the non-deterministic nature of rounding modes, NaNs and denormals, special care has to be made to ensure a deterministic environment on all supported platforms. This comes in the form of "softfloat", a software implementation of IEEE-754 float point arithmetic, which is constrained further to ensure determinism. If this determinism is not required, hardware based floating point operations are still available through a compile time define.

Any secondary limits/constraints (i.e. stack size, call depth, etc.) can cause consensus failures if these restrictions do not match any previous backend that was in place, EOS VM has all of these constraints user definable through either a compile-time system or run-time based on the use case and data type involved.

Time Bounded Execution

The ability to ensure that execution doesn't over run the CPU time that is allotted for a given program is a central component of a resource limited blockchain. This is satisfied by the watchdog timer system (as mentioned below, this mechanism is also useful for general security). EOS VM's implementation is both fast and efficient compared to prior solutions.

Two mechanisms are available to the user to bound the execution of Wasm:

  1. A simple instruction counter based bounding, this incurs a performance penalty, but doesn't require multi-threading.
  2. A watchdog timer solution that incurs no noticeable overhead during Wasm execution.

Secure by Design

WebAssembly was designed to run untrusted code in a browser environment where the worst that can happen is a hung browser. Existing libraries such as WABT, WAVM, and Binaryen were designed with assumptions which can lead to unbounded memory allocation, extremely long load times, and stack overflows from recursive descent parsing or execution.

The fundamental data types that make up EOS VM are built with certain invariants from the onset. This means that explicit checks and validations, which can be error-prone because of programmer forgetfulness, are not needed as the data types themselves maintain these invariants and kill the execution if violated.

In addition to these core data types, some of the special purpose allocators utilize the security of the CPU and core OS to satisfy that memory is properly sandboxed (a guard paging mechanism).

Because of the utilization of guard paging for the memory operations, host function calls that execute natively don't have to explicitly validate pointers that are passed into these functions if access outside of the sandboxed memory occurs, please note special care should be made to ensure that the host function can fail hard, i.e. not call destructors and have no negative impact.

At no point during parsing or evaluation does EOS-VM use unbounded recursion or loops, everything is tightly bound to limit or eliminate the ability for a bad or corrupt Wasm to cause a crash or infinitely hang the machine.

All of these solutions are transparent to the developer and allow for more succinct functions that are not cluttered with external checks and only the core logic is needed in most places.

High-Performance Execution

Host functions are callable through a thin layer that doesn't incur heavy performance penalties.

Because of the utilization of native paging mechanisms, almost all memory operations are very close to native if not at parity with native memory operations.

Because of the high compaction and linear nature of the builtin allocators, this allows for a very cache friendly environment and further allows for high performance execution.

Certain design decisions were made to maximize the performance of interpreter implementation. As mentioned above, EOS VM has custom allocators and memory management that fits the needs and use cases for different access patterns and allocation requirements. These allocators are used to back the core data types (fast vector, Wasm stack, fast variant, Wasm module), and as such do not "own" the memory that they use for their operations. These non-owning data structures allow for the ability to use the memory cleanly and not have to concern the data type with destructing when going out of scope, which can increase the performance for certain areas of EOS VM without loss of generality for the developer. Since the data is held by these allocators and have lifetimes that match that of a Wasm module, no copies of these heavyweight data types are ever needed. Once an element in an EOS VM is constructed, that is its home and final resting place for the lifetime of the Wasm module.

A fast variant or discriminating union type is the fundamental data type that represents a Wasm opcode or a Wasm stack element. This allows for a clean interface to "visit" each Wasm opcode without any loss of performance. This visiting is statically derivable and not dynamically dispatched like more classical approaches that use the object-oriented visitor pattern. In addition to a visit function that acts similar to std::visit, a custom dispatcher is defined that allows for a similar interface but with EOS VM specific optimizations and assumptions.

Effortless Integration

With the exception of the softfloat library, which is an external dependency, EOS VM is a header only implementation.

Given the needs of the end user, integration can be as simple as pointing to the include directory.

EOS-VM utilizes CMake which allows integration into a project to be as little as adding eos-vm to the list of targets in the target_link_libraries.

If the need is only single-threaded a self-contained backend type is defined for the user to encapsulate all the components needed, which allows for source code integration to be constructing an instance of that type and adding "host functions" to the registered_host_functions. Registering the host functions is as easy as calling a function with the function/member pointer and supplying the Wasm module name and function name.

If multi-threaded execution is needed (i.e. multiple backends running at once), then the above integration is needed and the user will have to also construct thread specific watchdog timers and linear memory allocators. These are also designed to be effortlessly registered to a particular Wasm backend.

Highly Extensible Design

Given the EOS-VM variant type and visitor system, new backends with custom logic can be easily defined and allows the same level of flexibility and code reuse as a much more heavyweight OOP Visitor or Listener design.

Since the design of EOS-VM is component based, with each component being very self-contained, new backends or tools for Wasm can be crafted from previously defined components while only needing to define the logic for the extended functionality that is needed, with very little, to no, boilerplate needed.

Extensions to Wasm itself can be made by simply defining the new section (aka C++ class field) for the module and the function needed to parse an element of that section. This will allow for tooling to be constructed at a rapid pace for custom Wasms for a multitude of needs (debugging, profiling, etc.).

Using EOS-VM

Quick Overview

Contributing

Contributing Guide

Code of Conduct

Important

See LICENSE for copyright and license terms.

All repositories and other materials are provided subject to the terms of this IMPORTANT notice and you must familiarize yourself with its terms. The notice contains important information, limitations and restrictions relating to our software, publications, trademarks, third-party resources, and forward-looking statements. By accessing any of our repositories and other materials, you accept and agree to the terms of the notice.

eos-vm's People

Contributors

arhag avatar b1bart avatar bytemaster avatar jeffreyssmith2nd avatar josephjguerra avatar kj4ezj avatar larryk85 avatar nksanthosh avatar norsegaud avatar scottarnette avatar spoonincode avatar swatanabe-b1 avatar tbfleming avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eos-vm's Issues

Memory leak in host calls

validate_ptr will siglongjmp from the signal handler if the pointer is out of bounds. This will bypass any destructors including those of aligned_array_wrapper. No intrinsics in nodeos can trigger this bug.

Build failure with glibc 2.34 or higher: SIGSTKSZ is no longer constant

When building against glibc 2.34, a build failure occurs rooted here due to the fact that SIGSTKSZ is no longer a constexpr value (see glibc changelog). There is also an error about a type mismatch in the arguments to max, but the 'interesting' error is the constexpr trouble.

This seems to be a trivial fix, as it appears that nothing depends on stack_cutoff being constexpr. Simply replace line 273 with:

std::size_t stack_cutoff = std::max<long>(252144, SIGSTKSZ);

BUG: parsing running wasm file causing crash

:eosio::vm::registered_host_functions<decltype(nullptr)>::operator()<eosio::vm::execution_context<decltype(nullptr)> >(decltype(nullptr)*, eosio::vm::execution_context<decltype(nullptr)>&, unsigned int) parsing running wasm file causing crash

CMakeFile cannot find 'pthread_create'

cmake CMakeLIst.txt

CMake command after Error log

Determining if the pthread_create exist failed with the following output:
Change Dir: /home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp

Run Build Command:"/usr/bin/make" "cmTC_5200c/fast"
/usr/bin/make -f CMakeFiles/cmTC_5200c.dir/build.make CMakeFiles/cmTC_5200c.dir/build

make[1]: Entering directory '/home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_5200c.dir/CheckSymbolExists.c.o
/usr/bin/cc    -o CMakeFiles/cmTC_5200c.dir/CheckSymbolExists.c.o   -c /home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp/CheckSymbolExists.c
Linking C executable cmTC_5200c
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_5200c.dir/link.txt --verbose=1
/usr/bin/cc      CMakeFiles/cmTC_5200c.dir/CheckSymbolExists.c.o  -o cmTC_5200c 
CMakeFiles/cmTC_5200c.dir/CheckSymbolExists.c.o: In function `main':
CheckSymbolExists.c:(.text+0x1b): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
CMakeFiles/cmTC_5200c.dir/build.make:97: recipe for target 'cmTC_5200c' failed
make[1]: *** [cmTC_5200c] Error 1
make[1]: Leaving directory '/home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp'
Makefile:126: recipe for target 'cmTC_5200c/fast' failed
make: *** [cmTC_5200c/fast] Error 2

File /home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp/CheckSymbolExists.c:
/* */
#include <pthread.h>

int main(int argc, char** argv)
{
  (void)argv;
#ifndef pthread_create
  return ((int*)(&pthread_create))[argc];
#else
  (void)argc;
  return 0;
#endif
}

Determining if the function pthread_create exists in the pthreads failed with the following output:
Change Dir: /home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp

Run Build Command:"/usr/bin/make" "cmTC_6007c/fast"
/usr/bin/make -f CMakeFiles/cmTC_6007c.dir/build.make CMakeFiles/cmTC_6007c.dir/build
make[1]: Entering directory '/home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_6007c.dir/CheckFunctionExists.c.o
/usr/bin/cc   -DCHECK_FUNCTION_EXISTS=pthread_create   -o CMakeFiles/cmTC_6007c.dir/CheckFunctionExists.c.o   -c /usr/share/cmake-3.10/Modules/CheckFunctionExists.c
Linking C executable cmTC_6007c
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_6007c.dir/link.txt --verbose=1
/usr/bin/cc  -DCHECK_FUNCTION_EXISTS=pthread_create    CMakeFiles/cmTC_6007c.dir/CheckFunctionExists.c.o  -o cmTC_6007c -lpthreads 
/usr/bin/ld: cannot find -lpthreads
collect2: error: ld returned 1 exit status
CMakeFiles/cmTC_6007c.dir/build.make:97: recipe for target 'cmTC_6007c' failed
make[1]: *** [cmTC_6007c] Error 1
make[1]: Leaving directory '/home/eos/Documents/eos.tools/eos-vm/CMakeFiles/CMakeTmp'
Makefile:126: recipe for target 'cmTC_6007c/fast' failed
make: *** [cmTC_6007c/fast] Error 2

Why CMake compile failed?

"wasm vector out of bounds" when running hello-driver example on Centos 7

I've built eos-vm on Centos 7.7, gcc 7.4 compiler.
When running tools/hello-driver I'm getting exception:
terminate called after throwing an instance of 'eosio::vm::wasm_vector_oob_exception'
what(): wasm vector out of bounds

Here is a stack:
#0 0x00007f6ff7548337 in raise () from /lib64/libc.so.6
#1 0x00007f6ff7549a28 in abort () from /lib64/libc.so.6
#2 0x00007f6ff7e8a135 in __gnu_cxx::__verbose_terminate_handler () at ../../.././libstdc++-v3/libsupc++/vterminate.cc:95
#3 0x00007f6ff7e87f26 in __cxxabiv1::__terminate (handler=) at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:47
#4 0x00007f6ff7e87f71 in std::terminate () at ../../.././libstdc++-v3/libsupc++/eh_terminate.cc:57
#5 0x00007f6ff7e881b3 in __cxxabiv1::__cxa_throw (obj=,
tinfo=0x4f2870 ,
dest=0x41410a eosio::vm::wasm_vector_oob_exception::~wasm_vector_oob_exception())
at ../../.././libstdc++-v3/libsupc++/eh_throw.cc:93
#6 0x0000000000414473 in eosio::vm::detail::vector<unsigned int, eosio::vm::growable_allocator>::at (this=0x7ffe2be97098, i=0)
at /home/alr/eos-vm/include/eosio/vm/vector.hpp:58
#7 0x000000000040d5b1 in eosio::vm::detail::vector<unsigned int, eosio::vm::growable_allocator>::operator[] (this=0x7ffe2be97098,
i=0) at /home/alr/eos-vm/include/eosio/vm/vector.hpp:76
#8 0x00000000004173c3 in eosio::vm::registered_host_functions<example_host_methods>::resolveeosio::vm::module (mod=...)
at /home/alr/eos-vm/include/eosio/vm/host_function.hpp:575
#9 0x0000000000412312 in eosio::vm::backend<example_host_methods, eosio::vm::interpreter>::backend<eosio::vm::registered_host_functions<example_host_methods> > (this=0x7ffe2be96f10, code=...) at /home/alr/eos-vm/include/eosio/vm/backend.hpp:48
#10 0x0000000000403c47 in main (argc=4, argv=0x7ffe2be974a8) at /home/alr/eos-vm/tools/hello_driver.cpp:66

Git pull/checkout/clone fails on Windows

Attempting to integrate this into CMake with the ExternalProject module. Git pull fails with various errors on Windows only; files (pretty much tests) include characters that give "invalid argument" errors (mainly colons and other characters disallowed by Windows in filenames). Is there a way this can either be fixed or ignored? As a result of this, git fails with the following error when pulling:

fatal: Could not reset index file to revision 'HEAD'.
Cannot rebase: You have unstaged changes.
Please commit or stash them.
No rebase in progress?

f32.demote_f64 fails

The parameters that cause a difference in behavior vs softfloat are not currently known. This may also affect the interpreter, but has not been tested.

Raise the limit on locals and stack

jit will currently fail if there are too many locals or stack variables. nodeos cannot hit this because the limits are higher than nodeos' limits.

Please publish your benchmarking reproduce process

It's interesting to see that eos-vm has excellent performance comparing to wabt and WAVM. But could you publish the exact benchmarking process (including build and run command) so that we could play with it too? Thanks!

Parsing of table may take too long

The table is fully instantiated by the parser, which may cause it to create a vector of 2^32-1 elements when parsing a small wasm, leading to potential DOS attacks. This is safe in nodeos for now, because the size of the table is bounded by validation, before eos-vm sees it.

Compile error in MacOS

Env: MacOS Catalina (also tried in OS version MacOS High Serria)
Clang:

  • Apple clang version 11.0.0 (clang-1100.0.33.8)
  • Target: x86_64-apple-darwin19.0.0
  • Thread model: posix
  • InstalledDir: /Applications/Xcode11.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
    (also tried in clang version 10.0.1)

llvm: 7.1.0 (also tried in llvm version 9.0.0)

Compile Error:

Scanning dependencies of target hello-driver
[ 98%] Building CXX object tools/CMakeFiles/hello-driver.dir/hello_driver.cpp.o
In file included from /Users/zhangyy/CLionProjects/eos-vm/tools/hello_driver.cpp:1:
In file included from /Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/backend.hpp:3:
/Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/allocator.hpp:213:45: error: no member named 'extract' in 'std::__1::set<std::__1::pair<unsigned long, void *>, eosio::vm::jit_allocator::by_size,
std::__1::allocator<std::__1::pair<unsigned long, void *> > >'
auto node = free_blocks_by_size.extract({lhs->second, lhs->first});
~~~~~~~~~~~~~~~~~~~ ^
/Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/allocator.hpp:174:27: error: no member named 'extract' in 'std::__1::map<void *, unsigned long, std::__1::less<void *>, std::__1::allocator<std::__1::pair<void *const, unsigned long> >
>'
auto node = from.extract(key);
~~~~ ^
/Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/allocator.hpp:106:10: note: in instantiation of function template specialization 'eosio::vm::jit_allocator::transfer_node<std::__1::map<void *, unsigned long, std::__1::less<void *>,
std::__1::allocator<std::__1::pair<void *const, unsigned long> > > >' requested here
transfer_node(free_blocks, allocated_blocks, best->second);
^
/Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/allocator.hpp:174:27: error: no member named 'extract' in 'std::__1::set<std::__1::pair<unsigned long, void *>, eosio::vm::jit_allocator::by_size,
std::__1::allocator<std::__1::pair<unsigned long, void *> > >'
auto node = from.extract(key);
~~~~ ^
/Users/zhangyy/CLionProjects/eos-vm/include/eosio/vm/allocator.hpp:107:17: note: in instantiation of function template specialization 'eosio::vm::jit_allocator::transfer_node<std::__1::set<std::__1::pair<unsigned long, void *>,
eosio::vm::jit_allocator::by_size, std::__1::allocator<std::__1::pair<unsigned long, void *> > > >' requested here
best = transfer_node(free_blocks_by_size, allocated_blocks_by_size, *best);
^
3 errors generated.
make[2]: *** [tools/CMakeFiles/hello-driver.dir/hello_driver.cpp.o] Error 1
make[1]: *** [tools/CMakeFiles/hello-driver.dir/all] Error 2
make: *** [all] Error 2

It seems Clang does not support C++17 feature map and set extract function.

rhs always got 0

[[gnu::always_inline]] inline void operator()(const i64_ne_t& op) {
     context.inc_pc();
     const auto& rhs = context.pop_operand().to_ui64();
     auto&       lhs = context.peek_operand();
     lhs             = i32_const_t{ lhs.to_ui64() != rhs };
  }

rhs always got 0 in gcc version 9.1.0 Ubuntu 18.04.3, but below code can get the right value.

[[gnu::always_inline]] inline void operator()(const i64_ne_t& op) {
     context.inc_pc();
     const auto& rhs = context.pop_operand();
     auto&       lhs = context.peek_operand();
     lhs             = i32_const_t{ lhs.to_ui64() != rhs.to_ui64() };
  }

Build errors compiling with header only mode

I'm trying to build the library in header only mode, when I compile I get the following error:

../external/eosio/vm/host_function.hpp:382:66: error: no member named 'apply' in
      'eosio::vm::detail::no_viable_overload_of_from_wasm<const std::__1::basic_string<char> &>'
            return detail::make_value_getter<S, Cons>().template apply<S>(alloc, static_cast<T&&>(val), tail);

I can't figure out what the issue is

bench-interp not working

testing rust code :

#[no_mangle]
pub fn main() -> u64  {
    let arr = [1,2,35,4,6,7,8];
    let mut sum  = 0;
    for i in 0..1000000000 {
        sum += arr[i % arr.len()];
    }
    sum
}

generated wasm file test.wat:

(module
  (type (;0;) (func (result i64)))
  (func (;0;) (type 0) (result i64)
    (local i32 i32 i64)
    get_global 0
    i32.const 64
    i32.sub
    tee_local 0
    i64.const 8
    i64.store offset=56
    get_local 0
    i64.const 7
    i64.store offset=48
    get_local 0
    i64.const 6
    i64.store offset=40
    get_local 0
    i64.const 4
    i64.store offset=32
    get_local 0
    i64.const 35
    i64.store offset=24
    get_local 0
    i64.const 2
    i64.store offset=16
    get_local 0
    i64.const 1
    i64.store offset=8
    i32.const 0
    set_local 1
    i64.const 0
    set_local 2
    get_local 0
    i32.const 8
    i32.add
    set_local 0
    loop  ;; label = @1
      get_local 0
      get_local 1
      i32.const 7
      i32.div_u
      i32.const -56
      i32.mul
      i32.add
      i64.load
      get_local 2
      i64.add
      set_local 2
      get_local 0
      i32.const 8
      i32.add
      set_local 0
      get_local 1
      i32.const 1
      i32.add
      tee_local 1
      i32.const 1000000000
      i32.lt_u
      br_if 0 (;@1;)
    end
    get_local 2)
  (table (;0;) 1 1 anyfunc)
  (memory (;0;) 16)
  (global (;0;) (mut i32) (i32.const 1048576))
  (export "main" (func 0)))

run cmd:

./bench-interp  test.wasm

output(I commented out the catch code in tools/bench_interp.cpp:37 , since it only print eos-vm interpreter error and no other useful information):

terminate called after throwing an instance of 'eosio::vm::wasm_memory_exception'
  what():  wasm memory exception
Aborted (core dumped)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.