What’s New in Chakra JavaScript Engine

A few weeks ago I decided to install Windows 10 Mobile Insider Preview on my Nokia Lumia 630 and played a little bit with it. Since then, I have completely forgotten about it until yesterday when I saw a notification for pending software update (10.0.12562.84). So I grabbed the opportunity to see what changed in Chakra JavaScript engine and JsRT API.

Overview

I am going highlight only some of the architectural changes in Chakra, for more information you can read MSDN documentation. Firstly, Microsoft decided to create new chakra.dll library and keep the old jscript9.dll library for compatibility reasons. This is a good decision because it allows shorter release cycles and provides some space for experimentation as well. Secondly, it seems that Microsoft is all into performance optimizations right now. Some of the most important optimizations are:

  • concurrent JIT compiler
  • new simple JIT compiler (when bailout happens)
  • improved polymorphic inline cache
  • equivalent object type specialization
  • bounds checking elimination (array optimization)
  • minified code optimization (sounds interesting and very promising)
  • concurrent mark-and-sweep GC (mark phase)

Lastly, with the upcoming ECMAScript 6 Microsoft decided to provide better support for it which is a big win for everybody.

JsRT

This is where it becomes interesting. As I work on NativeScript project, I would like to access WinRT APIs from JavaScript. In fact, Microsoft already supports this scenario in WinJS but I am interested in accessing all WinRT APIs and being able to build XAML based UI from JavaScript. Last September I blogged how to embed Chakra in Windows Phone 8.1 but back then this scenario was practically not supported by Microsoft. There wasn’t even jscript9.lib import library for ARM.

I am happy to say that those days are gone. Now, JsRT provides better support for WinRT projections. This is done through the following APIs:

  • JsProjectWinRTNamespace
  • JsInspectableToObject
  • JsObjectToInspectable

Let’s see how this works (I assume you have already installed Windows 10 Technical Preview and Visual Studio 2015 RC). Create new WinRT library project (Visual C++ -> Windows -> Windows Universal -> Windows Runtime Component). In my case I named it WindowsRuntimeComponent1 and created a simple Greeter class as follows.

namespace WindowsRuntimeComponent1
{
    public ref class Greeter sealed
    {
    public:
        Platform::String^ SayHello()
        {
            return ref new Platform::String(L"Hello");
        }
    };
}

Create an empty app (Visual C++ -> Windows -> Windows Universal -> Blank App) and add reference to the WindowsRuntimeComponent1 project. You have to define the macro USE_EDGEMODE_JSRT  in order to use the new JsRT API and link against chakrart.lib as well. Projecting WinRT classes is as easy as follows.

JsErrorCode err = JsProjectWinRTNamespace(L"WindowsRuntimeComponent1");
assert(JsNoError == err);

Now we are ready to consume the projected WinRT classes from JavaScript.

var g = new WindowsRuntimeComponent1.Greeter();
var s = g.sayHello();

I have to say that the debugging experience is almost perfect. I say “almost” only because I don’t see script debugging for ARM devices. I guess since this is Visual Studio 2015 RC it is a kind of expected. Also, you can always use script debugger on Windows Phone emulator since it is running x86 code.

You can find the sample project at GitHub.

Conclusion

Using the new JsRT together with Windows 10 Universal Application Platform (UAP) makes it easy to write apps that use JavaScript scripting. The good thing is that UAP guarantees that your apps will work across all kind of devices. There are some important limitations though:

  • cannot use XAML types (I guess it is still related to WebHostHidden attribute)
  • cannot extend types from JavaScript (again related to XAML)
  • cannot access Chakra in WinJS apps from WinRT components

I guess if you don’t want to build JavaScript/native bridges then the new JsRT is good enough. Resolving the above-mentioned issues will allow writing much more sophisticated apps though. Right now, you can use JsRT for simple scripting and nothing else. Making Chakra engine an open-source project will solve these and other issues. It will allow people to contribute to and customize the engine. Will it ever happen? Only time will tell.

Embedding Chakra JavaScript Engine on Windows Phone

Today I am going to show you how to embed Chakra JavaScript engine in Windows Phone 8.1 app. Please note that at the time of writing this app won’t pass Microsoft Windows Store certification requirements. I won’t be surprised though if Microsoft reconsider their requirements in future.

Last year Microsoft released JsRT which exposes C-style API for embedding Chakra JavaScript engine. To use the API you only need to include jsrt.h and add a reference to jsrt.lib. On my machine the header file is located at

C:\Program Files (x86)\Windows Kits\8.1\Include\um\jsrt.h

and the lib files (for x86 and x64 accordingly) are located at

C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86\jsrt.lib
C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x64\jsrt.lib

Curiously, there is no jsrt.lib for ARM architecture. It is even more interesting that JsRT is not exposed in Windows Phone SDK. E.g. you won’t find jsrt.h file in

C:\Program Files (x86)\Windows Phone Kits\8.1\Include

neither you will find jsrt.lib in

C:\Program Files (x86)\Windows Phone Kits\8.1\lib\ARM
C:\Program Files (x86)\Windows Phone Kits\8.1\lib\x86

However this shouldn’t discourage us. The first thing we should check is that JsRT API is exposed on Windows Phone 8.1. I know it is there because IE11 shares same source code for desktop and mobile and because Windows Phone 8.1 supports WinRT programming model. Anyway, let’s check it.

Find flash.vhd file. On my machine it is located at

C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.1\Emulation\Images

Use Disk Management and attach flash.vhd file via Action->Attach VHD menu. Navigate to \Windows\System32 folder on MainOS partition and copy JSCRIPT9.DLL somewhere. Open Visual Studio command prompt and run the following command

dumpbin /exports JSCRIPT9.DLL >jscript9.def

Open jscript9.def file in your favorite editor and make sure you see the full JsRT API listed here. Edit the file so it becomes like this one https://gist.github.com/anonymous/88e44e8931cc8d118da9. Run the following command from the Visual Studio command prompt

lib /def:jscript9.def /out:jsrt.lib /machine:ARM

This will generate import library so you can use all exports defined in JSCRIPT9.DLL library. We are almost ready.

We generated jsrt.lib import library for ARM architecture, what’s next? In order to use jsrt.h header in our Windows Phone 8.1 project we must edit it a little bit. First copy it and its dependencies to your project. Here is the list of all the files you should copy

  • activdbg.h
  • activprof.h
  • ActivScp.h
  • DbgProp.h
  • jsrt.h

In case you don’t want JavaScript debugging support you can copy jsrt.h file only and replace all pointers to the interfaces from ActiveScript API with void*. Once you copy the the header files you must edit them to switch to Windows Phone API. To do so, you have to replace WINAPI_PARTITION_DESKTOP with WINAPI_PARTITION_PHONE_APP. It may sound like a lot of work but it is just a few lines change. You can see the change here.

That’s it. Now you can use the new header and lib files in your project. You can find the full source code at https://github.com/mslavchev/chakra-wp81.

In closing I would like to remind you that at present this app won’t pass Windows Store certification requirements. Here is the list of the requirement violations

Supported API test (FAILED)
    This API is not supported for this application type - Api=CoGetClassObject. Module=api-ms-win-core-com-l1-1-1.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsCreateContext. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsCreateRuntime. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsDisposeRuntime. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsRunScript. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsSetCurrentContext. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsStartDebugging. Module=jscript9.dll. File=ChakraDemoApp.exe.
    This API is not supported for this application type - Api=JsStringToPointer. Module=jscript9.dll. File=ChakraDemoApp.exe.

Hopefully Microsoft will revisit their requirements.

Introduction to JsRT

I recently started working on a new project and part of it is about embedding V8 JavaScript engine. So far, my experience with V8 is very good. The object model is nice and clean and although the lack of a good documentation it is easy to work with it. I strongly recommend using V8, but in this post I am going to show you another option.

After I gained some know-how with V8, I decided to explore IE 11 Chakra JavaScript engine. Last week Microsoft announced IE 11 availability for Windows 7 and I guess it will become a good alternative to V8. I guess using Chakra engine may be tempting for developers that do not want to build V8 from source code or if they want to avoid static linking in order to keep small executable files.

For the sake of this introductory post, I am going to show you how to implement a simple printf-like functionality with Chakra (please note that I am going to provide just an overview, for more details see [1]). Suppose we want to implement a very simple print function that accepts some format string, an integer and a string and formats the output as shown.

native.printf('number=%#x string=%s\n', 255, 'test')

We are going to embed Chakra engine in a simple console app that runs this script and just outputs the result.

[Note: for the sake of brevity I am going to omit the error handling. The source code contains all the error checks though.]

The first thing we have to do is to create new Chakra JavaScript runtime. The runtime represents a complete JavaScript execution environment and has a single thread of execution.

JsRuntimeHandle runtime;
JsCreateRuntime(JsRuntimeAttributeNone, JsRuntimeVersion11, nullptr, &runtime);

Once we have created a runtime we have to create an execution context. There can be multiple execution contexts that are active on a thread at the same time.

JsContextRef context;
JsCreateContext(runtime, nullptr, &context);
JsSetCurrentContext(context);

Now, it is time to execute the script. This is done via JsRunScript function.

wstring script(L"native.printf('number=%#x string=%s\\n', 255, 'test')");
JsValueRef result;
JsSourceContext contextCookie = 0;
JsRunScript(script.c_str(), contextCookie, L"source", &result);

Right now, you are probably guessing where this native.prinft thing would come from. That’s right, I missed that part on purpose because I want to show the very basic workflow:

  • create a runtime
  • create a context
  • run the script

Let’s see what is needed to make native.printf to work. Every JavaScript runtime environment has one root object called global. This global object is the object that holds all top-level objects. So in our case we have to create a new object and make it accessible through native property on the global object. Then we have to create another object, actually a function, and make it accessible through printf property on the native object.

JsValueRef global;
JsGetGlobalObject(&global);

JsPropertyIdRef nativeProp;
JsGetPropertyIdFromName(L"native", &nativeProp);

JsValueRef nativeObj;
JsCreateObject(&nativeObj);

JsPropertyIdRef printfProp;
JsGetPropertyIdFromName(L"printf", &printfProp);

JsValueRef printfFunc;
JsCreateFunction(PrintFormat, nullptr, &printfFunc);

JsSetProperty(nativeObj, printfProp, printfFunc, true);
JsSetProperty(global, nativeProp, nativeObj, true);

The final missing thing is the PrintFormat callback function.

JsValueRef CALLBACK PrintFormat(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
{
	const wchar_t *format;
	size_t length;
	JsStringToPointer(arguments[1], &format, &length);

	VARIANT variant;
	JsValueToVariant(arguments[2], &variant);

	const wchar_t *str;
	JsStringToPointer(arguments[3], &str, &length);

	wprintf(format, variant.intVal, str);

	return JS_INVALID_REFERENCE;
}

That’s all. We implemented all the functionality required to execute native.printf function.

In closing I would say that using Chakra engine is fairly easy. The API is not object-oriented and some less experienced developers may find it as a drawback. On the other hand it is easy the incorporate Chakra C-style API in existing OO code base or use it from a script language like Python.

zipicon1Download source code

Further reading:

[1] MSDN