Archive

Posts Tagged ‘JavaScript’

Small is Beautiful

February 6th, 2012

Small JavaScript that is. Or how to go from 350 kB down to just… 25 kB 23 kB.

Smaller JavaScript can help in up to three ways:

  • faster download: faster application installation or startup.
  • faster parsing for the browser: faster startup.
  • smaller identifiers: faster execution for non-JITting JavaScript engines.

And smaller also means you can have far more complex applications for a given size budget.

Using Missile Command as illustration

MissileCommand is now available in the Chrome Web Store and in the Android marketplace, it’s built with Smart Mobile Studio, using the DWScript JS CodeGen.

The Pascal source for MissileCommand is made of about 10k lines of code (most of it from the VJL), and a “normal” build, results in 350kB of JavaScript, well formatted, readable and debug-able with clear variable & class names. That’s larger than Pascal source size by about 50%.

Starting from that, if you enable obfuscation, optimization for size and smart linking, the 350 kB go down to 100 kB of a JavaScript source (not really readable anymore), and when that source is packaged in an Android app or sent with HTTP compression, you’ll be looking at a 25 kB file.

For comparison, jQuery is 229 kB raw, and 31 kB minified & compressed, and jQuery UI is about twice larger than jQuery. And when you’ve taken all that baggage, you haven’t done anything yet!

Obfuscation

Obfuscation isn’t just to make your code more annoying to reverse engineer: it can also help make your JavaScript smaller.

When obfuscation is active, the CodeGen will replace most identifiers with shorter versions, usually 1 to 3 characters in length.

Since JavaScript is case sensitive, each extra character added to an identifier can take 62 different values (the CodeGen reserves “$” and “_” for special uses). So obfuscated identifiers are typically short, and that allows to save on space.

JavaScript is also quite heavy on hash-table name lookups, and smaller names help making hash computations faster. On a Desktop JavaScript engine, that advantage quickly fades away as the browser hot-spots profiler decides to JIT, but on your typical Smart-phone browser, the difference can be felt.

Optimize for Size

Optimize for size triggers two mechanisms in the CodeGen:

  • a JavaScript “minifier” is run on the output, it will strip away comments, useless spaces, tabs and other characters.
  • alternative code generation templates are used, which spit out less readable but smaller code. At this point, there is no choice between size and performance, only between more and less human-readable.

The minifier is applied to “asm” sections too, and performs “safe” minifications only.

Smart Linking

Just like in Delphi, smart linking will eliminate functions methods and classes you have in the Pascal source, but never use in your program.

This is where things break away from other JavaScript libraries in terms of size. At best, they offer manual smart-linking like  jQuery UI’s “Build Your Download“, or plain old plug-ins. But if you want to use those, it means you’ll be dealing with manually managing hundreds of different builds (given all the possible combinations), and will probably just be bundling useless stuff sooner or later, because life’s too short and/or time is money.

However, just like in Delphi, Smart Linking works best if your code is well decoupled, if you use dependency-injection and other light-coupling design approaches. So avoid coding spaghetti plates ;-)

At the time this article was written, the DWScript Smart-Linker limitations are :

  • virtual or interfaced methods of a class you use aren’t eliminated (same limitation as in Delphi) update 02/08: now supported, was simpler than anticipated.
  • there is no de-virtualization just yet (same limitation as in Delphi).
  • cross-referencing functions aren’t eliminated (procA calls procB, and procB calls procA), though as this may be more of a sign of a code smell, it might just be getting a compiler “hint” rather than smart-linker support.

Finally, Pascal being declarative and statically-typed (as long as you’re not abusing RTTI/asm stuff), the Smart-Linker will be able to go further than other optimizers that start from JavaScript (like Google’s closure), and thus have to accommodate for all potential dynamic tricks.

Tips , ,

Closures in DWScript / OP4JS

January 21st, 2012

Closures, also known as “anonymous methods” in Delphi, are now supported by DWScript for the JavaScript CodeGen, with the same syntax as in Delphi:

myObject.MyEvent := procedure (Sender : TObject);
                    begin
                       ...
                    end;

There are of course some extensions that go beyond what Delphi supports ;-)

You are allowed to use a named local procedure as a closure / anonymous method, with optional capture of local variables, allowing for neater layout of code, for instance:

begin
   ...
   procedure MyLocalProc(Sender : TObject);
   begin
      ...
   end;
   ...
   myObject.MyEvent := MyLocalProc;
   ...
end;

The function pointers and closures are unified, you did not have to distinguish between a “procedure” and a “procedure of object“, and you don’t have to distinguish a “reference to procedure” either, ie. if you declare

type TNotifyEvent = procedure (Sender : TObject);

as long as the parameters match (and result type for a function) , the above type will accept standalone functions, object methods, interface methods, and now closures/anonymous methods (and even record methods, which are just syntax sugar for standalone function with an implicit parameter).

PS: DWScript (as a scripting engine), will very likely evolve (in time) from a stack based-engine to a closure-based engine, so the above syntax will be supported for scripting purposes too, and not just when compiling to JavaScript.

News , ,

Good Practices for JavaScript “asm” sections in DWS/OP4JS

January 16th, 2012
Comments Off

The compiler supports writing “asm” aka JavaScript section in the middle of Object Pascal, there are a few good practices as well as tips to keep in mind, let’s review the menu:

  1. Name conflicts and obfuscation support
  2. Do you really need an “asm” section?
  3. Don’t rely on implicit parameters structure
  4. Handling callbacks with “Variant” methods
  5. Handling callbacks in an “asm” section
  6. Current limitations

1. Name conflicts and obfuscation support

This should be a point zero actually, but the first thing to have in mind is that you are allowed in Pascal to use as names identifiers that are reserved in JavaScript. Those can be language keywords (“this”, “delete”, etc.) or common DOM objects and properties (“document”, “window”).

The compiler automatically protects you from such conflicts by transparently renaming your identifiers (currently by adding a “$”+number at the end).

Then there is the obfuscator, which will basically rename everything to short, meaningless names. That’s good for more than obfuscation: it reduces the size of the JavaScript, improves the parsing and lookup-based performance in the browser.

The consequence is that in an “asm” section, you should prefix all Pascal identifiers with an ‘@’, so the compiler can correctly compile your asm. For instance in:

var window : String;
...
asm
   @window = window.name
end;

The ‘@window’ refers to the ‘window’ string variable (which the compiler will rename), while ‘window.name’ will be compiled “as is”, as it reads the ‘name’ property of the global ‘window’ JavaScript object.

2. Do you really need an “asm”‘ section?

Though for some weird cases you might (like this gem), there are many cases in which you don’t need “asm”, as the language supports a “Variant” type which is a raw JavaScript object, and upon which you can call methods, read properties directly or via indexes.

For instance, with v a Variant, the following code:

v := v.getNext();
v['hello'] := v.space + 'world';

will get compiled (almost) straight into

v = v.getNext();
v['hello'] = v.space + 'world';

When using Variant, you don’t have strong compile-time checks (it’s just you vs JavaScript), property and function names are case-sensitive, so use them with care. This is similar in syntax and essence to using OLE Variants and Delphi.

On the other hand, you have compiler support, and you get automatic casts when assigning a variant to a strong type (Integer, String, etc.), and you also get name conflict protection & obfuscation support without having to ‘@’ your Pascal references.

3. Don’t rely on implicit parameters structure

Because they may change in future compiler revisions!

For instance, methods are currently invoked with an implicit “Self” parameters, and the others behind, so currently “arguments[0]” is Self, and everything else if after that. But don’t rely on it.

Future compiler revisions may change that parameter’s name, may obfuscate it, may remove it entirely in favor of an implicit “this”, may inline your function, etc.

So if you need explicit parameters, declare them, if you’re in a method and need to access the object (Self), use “@Self”, if you need to access a field of the current object use “@Self.FieldName”, etc. That will keep working.

4. Avoid declaring variables in “asm” sections

Declare them in the parent function/method instead, and reference them with the ‘@’ prefix.

There are three main reasons for that, the first is that doing so means they’ll be case-insensitive, the second is that it will allow the obfuscator to obfuscate them reason for that, and the third is that you’ll get compiler warnings if you declare a variable but do not use it (or if you forgot to @-prefix it).

So don’t write that:

asm
   var myTemp;
   myTemp = ...whatever...;
   ...
end;

But write this instead:

var myTemp : Variant;
...
asm
   @myTemp = ...whatever...;
   ...
end;

5. Handling callbacks with “Variant” methods

A common occurrence is to register a callback to a JavaScript object, when that object is hosted in a Variant, that’s fairly simple to achieve:

procedure DoImageLoaded;
begin
   ...
end;
...
var myImage : Variant; // will refer to an image object
...
myImage.onload(@DoImageLoaded);

There we use the ‘@’ operator Pascal-side, to make it explicit that we want a function pointer, and not call the function. The ‘@’ isn’t necessary when the function is declared Pascal-side, as the compiler can figure it out, but when invoking a Variant method, it doesn’t know the parameters type.

Note that since function pointers are unified, you can get a function pointer from an object method or an interface method in the same fashion:

myImage.onload(@myObject.DoImageLoaded);
myImage.onload(@myInterface.DoImageLoaded);

6. Handling callbacks in an “asm” section

If you want to register the callback in an “asm” section, the situation is a little more complex, as “@myObject.myMethod” will refer to the function prototype, outside of its context. It means it’s okay for standalone functions or procedures, but may not do what you’re expecting for object or interface methods.

The solution is to acquire the function pointer outside of the “asm” section:

var myCallback : Variant;
...
myCallback := @myObject.DoImageLoaded;
asm
   @myImage.onload(@myCallback);
end;

7. Current limitations

Currently the parser for “asm” sections doesn’t really understand JavaScript:

  • it’s still treating JS as a weird invalid form of Pascal, and notably {} define comments for it, so it will pass whatever is inside curlies “as is”, and will annoyingly ignore @ signs inside curlies
  • some weird operator combos (but valid JS)  may throw off the parser, if that happens, place that code in between curlies, and post a bug report

Hopefully in time, there will be a proper JS parser, but currently the focus is more on the Pascal side, and “asm” sections are intended for handling corner cases more than as a main workhorse.

Tips , , ,

OP4JS: “How do I…”

January 6th, 2012
Comments Off

Taming the Chrome Web Store

September 30th, 2011
Comments Off

Chromium LogoWell, “taming” is probably too ambitious given the jungle that the Chrome Web Store is, especially as this post is restricted to publishing a standalone DWScript/JavaScript app into the Web Store in a few simple steps. Interestingly enough, it seems that publishing Metro apps for Windows 8 will follow a similar process, according to the developer preview.

I’ll use the Flock Demo as an illustration, and turn it into a packaged app, that lives in Chrome and can be access off-line.

Bare minimum requirements

First prepare a folder for the app, in that folder you’ll need all your sources and resources (html, js, images, etc.), in our case, that’s just

  • flock.htm
  • jquery.js

For more complex cases, you are allowed to have sub-folders to neatly arrange everything.

The extra required Chrome package files are, at a bare minimum:

  • manifest.json
  • 16×16 icon (PNG format)
  • 128×128 icon (PNG format)

The manifest.json I used is the following

{
  "name": "DWScript Flock Demo",
  "version": "1.5",
  "description": "Interactive Canvas demonstration for DWScript",
  "app": {
    "launch": {
      "local_path": "flock.htm"
    }
  },
  "icons": {
    "16": "icon_16.png",
    "128": "icon_128.png"
  }
}

Note that the specs for manifest.json are rather “raw”, and if you get something wrong, you’ll likely fail your submission, and each failed attempt, if it’s not caught during upload, will be result in an error at install time. When you re-upload you need to specify a new version number (that’s why it’s at 1.5 in the above snippet!).

Testing and publishing the packaged app

To minimize issues, you can test your app as an unpackaged app in Chrome, go to tools/extensions, then activate the “developer mode”. You’ll then be able to specify the folder in which you placed your app. This also allows to run everything with the developer tools (debugger, etc.).

Once you’re confident enough, you can upload to the Web Store, for that just zip your folder and submit it. The zip can hold sub-folders, but make sure your manifest is at the root of the zip. Be aware there is $5 one-time, lifetime fee per Web Store developer account (not per app).

Then you’ll have the choice of publishing to testers or to end users, that choice is currently final, ie. if you publish to testers, you’ll have to create another web store entry for the user version. Note that there is a small delay between publishing an update, and the update being available for installation.

Finally, all that’s left is a bit of marketing, preparing a screen-shot or two, a YouTube video, a promotional tile, etc. If you’re on a budget, you can use CamStudio to grab the video.

See DWScript Flock Demo on the Chrome Web Store.

As a packaged app, it’ll be available in Chrome from the “Applications” bar of a new tab (Ctrl+T), you can also view them in the context menu.

Tips , ,

Taming the flock with Object Pascal

September 28th, 2011

And now for a more interactive demo than last time, this is a full-screen HTML5 Canvas interactive demo with the source in Object Pascal, compiled to JavaScript by the DWScript JS CodeGen. Click below to see it in action and hit F11.

Click-me, I'm best seen in action!

It illustrates using records, classes, and invoking the HTML5 Canvas and jQuery directly from Pascal code.

Chrome handles it best, but IE9 and FireFox are doing reasonably fine.

This time, I’ve wrapped it up in a demo zip (653 kB), where you can have a look at the DWScript code, the Delphi code required to compile & run the demo, and you can even fiddle with the source and over-simplified compiler options (Debug/Release/Obfuscated) with the included pre-compiled executable.

To compile the demo yourself, you’ll need DWScript (SVN version), SynEdit (SVN version) and Indy (the version included with Delphi XE should be okay), which is used for a mini-web server to allow running the demo directly in your favorite browser.

Ideas ,

Taming HTML5 verlets with Object Pascal

September 19th, 2011

Click the image below for a little real-time verlet integration animation.

And the source code for that little bit of HTML5 animation is Object Pascal, Delphi Web Script flavor, and is posted below.

It shows off the inline method implementations (you can use classic implementation style, and if that code were in a unit, you would have to), along with the extended Variant syntax. If you look at the HTML source, it also shows off output from an early version of the obfuscator/minifier.

FireFox6 and IE9 handle it fairly well, but Chrome just laughs at it and taunts you to bring it on. Runs on all major mobile platform too, at a reduced framerate of course, but not in slide-show mode (and on Android, FireFox Mobile is king of the hill).

<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<canvas id="canvas" width="300" height="400"></canvas>
<script>
<%pas2js

type 
   TVerletPoint = class
      private
         FX, FY : Float;
         FOldX, FOldY : Float;

      public
         procedure SetPosition(aX, aY : Float);
         begin
            FX := aX; FOldX := aX;
            FY := aY; FOldY := aY;
         end;

         constructor Create(aX, aY : Float);
         begin
            SetPosition(aX, aY);
         end;

         procedure Update;
         begin
            var dx := FX - FOldX;
            var dy := FY - FOldY;
            FOldX := FX;
            FOldY := FY;
            FX := FX + dx;
            FY := FY + dy;
         end;

         function DistanceTo(p : TVerletPoint) : Float;
         begin
            Result := Sqrt(Sqr(p.FX-FX)+Sqr(p.FY-FY));
         end;

         property X : Float read FX write FX;
         property Y : Float read FY write FY;
   end;

type
    TVerletStick = class
      private
         FDistance : Float;
         FA, FB : TVerletPoint;

      public
         constructor Create(pA, pB : TVerletPoint);
         begin
            FA := pA;
            FB := pB;
            FDistance := pA.DistanceTo(pB);
         end;

         procedure Apply;
         begin
            var dx := FA.X - FB.X;
            var dy := FA.Y - FB.Y;
            var d := Sqrt(dx*dx+dy*dy);
            var f := (d - FDistance) * 0.5 / d;
            FA.X := FA.X - dx * f;
            FB.X := FB.X + dx * f;
            FA.Y := FA.Y - dy * f;
            FB.Y := FB.Y + dy * f;
         end;

         property A : TVerletPoint read FA;
         property B : TVerletPoint read FB;
   end;

const cCOLS = 30;
const cROWS = 25;
const cSPACING = 10;
var points : array of TVerletPoint;
var sticks : array of TVerletStick;

procedure InitGrid;
var
   r, c : Integer;
   point : TVerletPoint;
begin
   for r:=0 to cROWS-1 do begin
      for c:=0 to cCOLS-1 do begin
         point:=new TVerletPoint(c*cSPACING, r*cSPACING);
         points.Add(point);
         if c>0 then
            sticks.Add(new TVerletStick(points[r*cCOLS+c-1], point));
         if r>0 then
            sticks.Add(new TVerletStick(point, points[(r-1)*cCOLS+c]));
      end;
   end;
end;

procedure UpdateGrid(canvas : Variant);
var
   i, j : Integer;
   stick : TVerletStick;
begin
   for i:=0 to points.High do begin
      points[i].Y := points[i].Y + 0.1; // gravity
      points[i].Update;
   end;
   for i:=1 to 3 do begin
      points[0].X := 0;
      points[0].Y := 0;
      points[cCOLS-1].X := (cCOLS-1)*cSPACING;
      points[cCOLS-1].Y := 0;
      for j:=0 to sticks.High do begin
         sticks[j].Apply;
      end;
   end;

   canvas.clearRect(0, 0, 300, 400);
   canvas.beginPath();
   for i:=0 to sticks.High do begin
      stick:=sticks[i];
      canvas.moveTo(stick.A.X, stick.A.Y);
      canvas.lineTo(stick.B.X, stick.B.Y);
   end;
   canvas.stroke();
end;

InitGrid();

procedure Animate(stepFunc : procedure(canvas : Variant)); external;

Animate(UpdateGrid);

%>

var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
canvas.strokeStyle = "black";
canvas.lineWidth = 0.8;

function Animate(f) {
    setInterval(
        function () {
            f(context);
        },
        10);
}

</script>

Source loosely based on Alex Nino’s.

Tips , ,

Status of the DWS JavaScript CodeGen

September 12th, 2011

JavaScript CodeGen for DWScript: what works, what doesn’t

Pretty much everything is working, including class methods (virtual or not), var & lazy parameters, records, arrays (dynamic and static), functions/method pointers/delegates, interfaces, operator overloading, etc. in short, the list of “what works” would amount to listing almost every DWS language feature, so I’ll just list what isn’t supported instead, or supported with quirks.

Of course, take this list with a grain of salt, it may be obsolete in the near future ;-)

Destructors: JavaScript doesn’t exactly have the concept, you can just “delete” and null fields. Though DWS being garbage-collected, destructors are in DWS more for compatibility with Delphi and special tasks, and you can often go on just fine without them. In practice the limitation is that in a Delphi-side execution, when an object is GC’ed, it’s destructor code will be executed, while on the JS-side, a destructor will only get executed if manually invoked.

DateTime: Date/Time functions are currently not supported JS-side. Though contrarily to the rest of the RTL functions, these will involve a rather heavy framework, as JavaScript built-in features for manipulating or converting date & time are rather lacking.

Variants: they are supported only in limited cases, mostly revolving around passing them around, f.i. as parameters. The reason they aren’t in lies with figuring out what should happen when you do cross-type operations and comparisons (f.i. when comparing a string to a variant, a variant to a string, etc.). The JS resolutions for those are different than Delphi’s, and to be honest, I’m not really sure what the Delphi rules are in all the cross-type cases in the first place. Another option being considered is to not worry about Delphi-side behaviors, and just use the JS behaviors.

StackTrace: Exception’s StackTrace member isn’t supported yet. At the moment stack traces in JS involve browser-specific code, so this may require a significant framework.

ExceptObject: this is a special entity that in Delphi allows to access the current exception, there is AFAIK no direct equivalent in JS, and emulating it would involve a significant amount of extra JS code. Since its usage scenarios are infrequent, it is currently of low priority.

News ,

First look at XE2 floating point performance

September 2nd, 2011

With XE2 now officially out, it’s time for a first look at Delphi XE2 compiler floating point performance (see previous episode).

For a first look I’ll reuse a Mandelbrot benchmark, based on this code Mandelbrot Set in HTML 5 Canvas. What it tests are double-precision floating-point basic operations (add, sub, mult) in a tight loop, there is relatively little in the way of memory accesses (or shouldn’t be, to be more accurate).

You can find the source code see there, it compiles pretty much straight away in XE2 (just comment out  the asm for Win64).

NOTE: when this article was originally posted, I had stumbled upon an XE2 Trial version “trap” (or feature?) which basically deactivated Win64 optimizations as defined through the project options. Kenji Matumoto pointed the issue, and this is an updated article where I used {$O+} in the code to “force” optimizations. The outcome is a *much* prettier picture, I’m happy to say! Reservations from the initial articles are gone, good job Embarcadero!

edit 05/09, after further tests, I’m adding one reservation single-precision floating point doesn’t look so hot. More on the subject there.

Benchmark results

Without further ado, here are the raw figures on my machine for the 480 x 480 case, keep in mind the Delphi versions do NOT use Canvas.Pixels[], but direct memory access in an array:

Execution time in milliseconds, lower is better

Or if you prefer hard figures:

  • Delphi XE2 – 32 bits: 193 ms
  • Delphi XE2 – 64 bits: 67 ms — fastest Delphi
  • Delphi XE: 196 ms
  • FireFox 6: 121 ms
  • Chrome 13: 74 ms
  • (out of competition: XE 32bit hand-made assembly: 57 ms)

So what gives?

  • XE2 32bit compiler still uses the old FPU code, the performance delta with XE is minimal and could just be an alignment issue (pseudo-random, since the compiler doesn’t pro-actively align). Let’s hope the SSE2 codegen will be retrofitted in XE3.
  • XE2 64bit compiler get a nice boost from using SSE2, allowing it to catch up and overtake all JavaScript JITters.
  • Chrome V8 makes a good showing in this benchmark, but loses the crown, native Delphi is back on top!

A peek under the hood

What does the compiler generate for the two following lines?

x := x0 * x0 - y0 * y0 + p;
y := 2 * x0 * y0 + q;

Once you pop up the CPU view, you’ll see:

FMandelTest.pas.193: x := x0 * x0 - y0 * y0 + p;
00000000005A1452 660F28C4         movapd xmm0,xmm4
00000000005A1456 F20F59C4         mulsd xmm0,xmm4
00000000005A145A 660F28CD         movapd xmm1,xmm5
00000000005A145E F20F59CD         mulsd xmm1,xmm5
00000000005A1462 F20F5CC1         subsd xmm0,xmm1
00000000005A1466 F20F58C2         addsd xmm0,xmm2
FMandelTest.pas.194: y := 2 * x0 * y0 + q;
00000000005A146A 660F28CC         movapd xmm1,xmm4
00000000005A146E F20F590DA2000000 mulsd xmm1,qword ptr [rel $000000a2]
00000000005A1476 F20F59CD         mulsd xmm1,xmm5
00000000005A147A F20F58CB         addsd xmm1,xmm3

And further down the code, the compiler makes use of xmm8, so it’s really aware of the 16 xmm registers you have in x86-64, and finally keeps floating poitn value in registers, something the 32bit compilers (both XE & XE2) don’t do.

To what does it lose to the hand-made asm version? Well a handful of minor things:

  • even though it used up to 9 xmm registers, it didn’t use 10th, leaving some memory access
  • with more careful allocation, it could have fit everything in 8 xmm registers, which would have cut unnecessary traffic
  • it zeroes register with a move from memory,  didn’t do constant unification or propagation.

Still those are mostly nitpickings compared to the massive issues of the old FPU code compilation (which, alas XE2 – Win32 still suffers from).

Conclusion

Support for SSE2 in XE2 64bit compiler consists in a significant step ahead for Delphi floating point performance. XE2 32bit is still same old.

If you’re doing heavy floating point maths, XE2 64bit compiler is a simple ticket to much better performance.

Hopefully in Delphi XE3 they will retrofitting the SSE2 codegen into the 32bit compiler, but ad interim it should quell all the critics about “we don’t need no 64bit”, well, if you do any significant floating-point maths, Delphi XE2 64bit is a must!

News , , ,

DWScript to JavaScript

July 26th, 2011

Not exactly breaking news for those following the OP4JS news or the DWS SVN, but a new experimental set of classes is available for DWScript, which allows compiling DWScript source into JavaScript.

This allows to have Pascal code like this one for instance, be compiled into this html page (or see the outcome in jsfiddle), and be executable client-side by any modern browser (the demo uses HTML5′s Canvas). In the DWS source repository, you’ll find it in “MandelbrotJS” (requires Delphi Chromium Embedded to run).

The goal is to allow using a strongly typed, compile-time checked language in a Web-client environment. The code generation is also intended to be as lightweight as possible, without depending on a huge framework, and generate quite readable-looking JavaScript.

In the classic Delphi spirit, it’s all about allowing both a high-level usage, while still being open to low-level usage whenever you wish or need  to.

The compiled Pascal functions can be used for DOM events or called from JS, or vice-versa, and you are f.i. able to use it only for the more complex routines or libraries for which straight JavaScript’s lack of strong typing and prototype-based objects would make it a developer-intensive and bug-prone approach.

This is still work in progress, only a (growing) subset of the DWS runtime library functions are supported at the moment, but most of the language is in working condition, including var parameters, classes, meta-classes, virtual methods & constructors, exceptions, bounds checking, contracts, etc. Currently, more than 85% of the DWS language & rtl unit tests pass (most of those not passing are related to Variants, destructors & ExceptObject).

The JS CodeGen can be invoked directly or via DWS filters, so you can have a single-source DWS code with portions running either server-side or browser-side.

FWIW, the DWS CodeGen classes were originally intended for compiling to SSE2-optimized floating point, either directly to x86-64 or via LLVM, but JavaScript is at the moment opening more opportunities, and modern JS engines are making decent use of SSE2 already. Last but not least, in the near term, it’s probably best to let the dust of the upcoming Delphi XE2 settle a bit ;-)

News ,