In the forums there was a post about a detailed description of the compiler options. Since there are currently no in-depth information available this post tries to clarify the topic a bit.
Let’s first start with the basic compiler options as can be seen in the screenshot below:
Basic Compiler Options
Unter ‘Compiler Options’ the user can adjust the internal DWScript compiler, which is responsible for compiling the Object Pascal source code into an internal representation. While the DWScript compiler offers a few more options, these are the only ones the user can play with.
Assertions
If ‘Assertions’ is checked statements like Assert(BoolExpression) will be compiled. If you’re not familiar with asserts, just think of them as additional stability checks you can add every here and there. They are translated to something like:
if not BoolExpression then raise EAssertionFailed.Create('Assertion failed');
where the Boolean experession can be something like “SomeValue < AnotherValue” or a function call like “IsValueValid(SomeValue)”.
As soon as any assertion appears in your source code the following lines will be added to your JavaScript source code:
var EAssertionFailed={ $ClassName: "EAssertionFailed", $Parent: Exception, $Init: Exception.$Init } function $Assert(b,m,z) { if (!b) throw Exception.Create($New(EAssertionFailed),"Assertion failed"+z+((m=="")?"":" : ")+m); }
If you uncheck this option, the entire statement will be replaced by /* null */ in the JavaScript source code. If you call a function in that expression, it won’t be called at all. So be careful to only put checks in an assertion.
Optimization
If ‘Optimization’ is checked the internal coOptimize is passed to the DWScript. This triggers several countless optimizations in the DWScript compiler. A detailed list of what this influences is yet missing, but in general it tries to omit empty statements or eliminate dead code. Here’s a brief list of what is done
- removes empty initialization/finalization blocks
- optimizes const assignments (not active in some versions)
- optimizes function expressions (e.g. constant functions -> constants)
- optimize comparisons (constant comparison is done at compile-time)
- …
It adds another pass to the compilation, which results in longer compilation times.
NOTE: At the time of writing it seems as if this option is not taken into account (even if enabled) in Smart Mobile Studio due to an improper setup. It will be fixed as soon as possible.
Hints
With ‘Hints’ several options about the hinting level of the compiler are available. If set to ‘Disabled’ no hints will be shown in the compiler message list. If set to ‘Normal’ the usual hints are emitted. Even more hints are emited with ‘Strict’ and in ‘Pedantic’ it will even complain differences in case sensitivity. The latter can be in particular useful if interfacing the case sensitive JavaScript language.
Predefined Conditions
The predefined conditions are nothing more than a convenient way to specify some compiler definitions. These correspond to:
- Handle uncaught exceptions -> {$DEFINE SMART_INTERNAL_HANDLE_EXCEPTIONS}
- Automatically refresh in the browser -> {$DEFINE SMART_INTERNAL_AUTO_REFRESH}
- Legacy support for IE9 (and below) -> {$DEFINE SMART_LEGACY_INTERNET_EXPLORER}
and will be set at a compiler level (for all units).
In addition the linker will output a file called ‘timestamp.txt’ if the ‘Automatically refresh in the browser’ is checked. This will be used to identify if the file has been changed.
Custom conditional defines
In addition to the predefined conditions you can specify custom conditional defines. These will add to the compiler and similar to the predefined conditions set at the compiler level (i.E. set in all units).
Code Generation
Previously the DWScript compiler options were described. This section now covers the code generation options. These correspond to the DWScript JSCodeGen, which was to some point available as open source. As it hasn’t evolved much in regards of the basic options, you can still find it around if you need more details.
The ‘Code Generation’ section is combined with the ‘Runtime Checks’ section. The latter sits in between the compiler and the code generation as it adds runtime checks at compile time, which are then transpiled to JavaScript.
Inline Magic
With inline magic the compiler will inline the DWScript’s mini RTL functions: AnsiLowerCase, AnsiUpperCase, ArcCos, ArcSin, ArcTan, ArcTan2, Ceil, Cos, Copy, MidStr, Exp, FloatToStr, Floor, Format, HexToInt, Infinity, IntPower, IntToHex, IntToStr, IsFinite, IsNaN, LeftStr, Ln, LowerCase, Max, Min, MaxInt, MinInt, NaN, Pi, Pos, PosEx, Power, Round, Sign, Sin, Sqr, Sqrt, StrBeginsWith, StrDeleteLeft, StrContains, StrFind, StrJoin, StrMatches, StrSplit, StrToFloat, StrToInt, SubStr, SubString, Tan, TypeOf, Unsigned32, UpperCase, VarIsNull, VarIsClear and VarIsArray with direct JS code instead of call them as functions.
This typically speeds up the application as typically less code is generated.
Emit RTTI information
With ‘Emit RTTI information’ the compiler will output RTTI information. It can be left unchecked if no RTTI is needed.
Ignore published in implementation
No information available so far.
De-virtualization
Often methods are declared as virtual, but there is no override used in the source code. In this case it might make sense to unmark it as virtual to improve its performance upon calls. Since it is cumbersome to maintain by hand (especially if overrides are planned to be implemented in the future) and sometimes difficult (if an overrided function doesn’t call the inherited function) to find, this feature de-virtualizes your code.
The feature takes time to perform, but might result in a major boost if enough de-virtualize opportunities exist (ie. if virtual methods are not called directly or indirectly in initialization sections or constructors)
Emit source locations
This controls whether source locations are emitted or not. This feature links to the verbosity options.
Smart linking
Checks if the function is used at all. If not, it is not generated at all.
As a dedicated stage in the code generation process this takes time, but it might be well worth it. In order to work decently, the units shouldn’t have much cross-dependencies.
NOTE: This feature still contains a bug for functions that are only called from within a lambda statement.
Code packing
If enabled the code will be packed by stripping empty lines. It is marked as recommended, especially for a release.
Code obfuscation
If enabled the code will be obfuscated by replacing the function names with strings from a random generator. This will make deciphering of the JS source code much harder.
It is marked as recommended, especially for a release, when it is important to protect your source. If you want others to read your code, you should of course uncheck this option.
NOTE: Class names will not be obfuscated as RTTI or other functions such as comparing the ClassName won’t work. This is important to know as this can be the reason why tools like Google’s closure compiler might not work as expected although it does similar techniques like obfuscation.
Use main body
If ‘Use main body’ is checked the entire code is wrapped into a main function by the compiler. This might or might not necessary depending on the context where you want to use the script. For example the default HTML template already adds another main body, so it might not be needed.
A ‘main body’ in this context means:
var $Application = function() {
// your code will appear here
}
$Application();
Especially for environments where less is more (e.g. microcontroller programming), this just adds an unnecessary overhead.
Verbosity
With ‘Verbosity’ the verbosity of the generated JavaScript code can be controlled. If set to ‘None’, the JavaScript output will not contain any comments that link to the original Object Pascal source. With ‘Normal’ it will contain comments with the function names and position in the original source code. And with ‘Verbose’ it will contain even more comments (about the classes etc.).
Runtime checks
If checked the code generation will add several runtime checks. JavaScript itself is not very critical so eventually an access beyond the bounds might just create a new field you are not aware of.
For example the code below will compile and run without complains.
var MyArray: array [0 .. 1] of Integer; for var Index := 0 to 9 do MyArray[Index] := Index;
As can be seen easily the code is not doing right as the array index clearly exceeds the range of elements. This would result in a hidden issue that can be very hard to locate. With ‘range checking’ enabled, an exception is raised, which points you to the location in the source code where the range is exceeded.
NOTE: Due to a bug in the, range checking does not work with the code below when the array is allocated dynamically:
var MyArray: array of Integer; MyArray.SetLength(2); for var Index := 0 to 9 do MyArray[Index] := Index;
This bug will hopefully be fixed in one of the next versions.
Other runtime checks include
- Instance checking
- Condition checking
- Loop step checking
At the time of writing several issues in the IDE could be revealed. These will (hopefully) be fixed and the article will be revised in the future.
This also includes items that are not yet described perfectly clear in this article.
The bug mentioned at the end of the article (about dynamic arrays being not properly checked) will be fixed with the next hotfix.