JavaScript interoperability

Alessandro Pignotti edited this page Oct 20, 2016 · 6 revisions

Cheerp implements three advanced interoperability mechanisms to interface C++ code with pure JavaScript:

  • Expose C++ classes and methods to JavaScript code
  • Inlining JavaScript code within a C++ codebase.
  • Use JavaScript methods and classes directly from C++

The jsexport attribute

The [[cheerp::jsexport]] attribute can be applied to C++ class and struct definitions, to expose them to JavaScript. The compiler currently imposes some limitations on the class:

  • The class must not use virtual methods or inherit from any class that does;
  • The class must have a trivial destructor, which means that all base classes and members must have a trivial destructor as well;
  • Member fields can't be accessed from JavaScript, only methods can.

We are planning to waive these limitations in future releases of cheerp. Requiring that the class has a trivial destructor means that no custom operation can happen within the destructor. This allows to fully rely on the JavaScript garbage collector to clean up the object.

See the example below:

class [[cheerp::jsexport]] JsStruct
        float a;
        int b;
        JsStruct(float _a, int _b):a(_a),b(_b)
        void test()
                client::console.log("Invoked test");

This example exposes the JsStruct class, and allows to create and use the JsStruct instances from JavaScript, for example:

var testExport = new JsStruct(3.0, 42);

The asm keyword

A different mechanisms allows to inline JavaScript code in the middle of a C++ application. Similarly to a traditional architecture, the __asm__ keyword permits to write native (JavaScript) code. This functionality can be used to interface with external JS libraries which have no Cheerp compatible headers yet. As of now, there is not support to returning values and passing arguments.

The following is a simple example of JavaScript inlining in C++:

__asm__("alert('Alert from __asm__')");

The client namespace

Cheerp treats every function and class inside the client namespace as a declaration for something implemented by the browser or JavaScript. You are free to add new declarations there for functions implemented in JavaScript. For example:

namespace client
    int someJavaScriptMethod(int arg1, const String& arg2);

void webMain()
    printf("JavaScript returned %i\n", client::someJavaScriptMethod(42, "This is converted to a JavaScript String"));

And on the JavaScript side:

function someJavaScriptMethod(arg1, arg2)
    return arg1 - arg2.length;