Purpose: Features JavaScript execution using the SpiderMonkey library
- this unit is a part of the freeware Synopse framework, licensed under a MPL/GPL/LGPL tri-license; version 1.18
Unit Name | Description | |
---|---|---|
SynCommons | Common functions used by most Synopse projects | |
SynLog | Logging functions used by Synopse projects | |
SynSMAPI | SpiderMonkey *.h header port to Delphi | |
SynTable | Filter/database/cache/buffer/security/search/multithread/OS features | |
SynTests | Unit test functions used by Synopse projects |
Objects | Description | |
---|---|---|
ESMException | Generic parent class of all SpiderMonkey-related Exception types | |
TSMEngine | Implements a ThreadSafe JavaScript engine | |
TSMEngineManager | Main access point to the SpiderMonkey per-thread scripting engines | |
TSMEngineMethodEvent | Used to store one registered method event | |
TSMObject | Just a wrapper around JavaScript Object API type, to be used with other values wrappers | |
TSMValue | Just a wrapper around jsval API type, to be used with our object wrappers | |
TSMVariant | A custom variant type used to store a SpiderMonkey object in Delphi code | |
TSMVariantData | Memory structure used for TSMVariant storage of any JavaScript object as Delphi variant |
ESMException = class(ESynException)
Generic parent class of all SpiderMonkey-related Exception types
TSMValue = object(TObject)
Just a wrapper around jsval
API type, to be used with our object wrappers
- SpiderMonkey jsval
type can be directly casted to this type via TSMValue
(jsval
)
- note that some methods expect an execution context to be supplied as parameter, as soon as it contains a non primitive type (double/integer)
function SetJSON(cx: PJSContext; const aJSON: RawUTF8): boolean;
Set the value from UTF-8 encoded JSON
- returns TRUE if aJSON was valid, FALSE in case of an error
function ToBoolean: boolean;
Read the value as boolean
function ToDateTime(cx: PJSContext): TDateTime;
Return the value as a date/time
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
function ToDouble: double;
Read the value as floating point
function ToInt64: int64;
Read the value as one 64 bit integer
- note that SpiderMonkey is not able to store all Int64 values directly
function ToInteger: integer;
Read the value as one 32 bit integer
function ToJSON(cx: PJSContext): RawUTF8;
Return the value as UTF-8 encoded JSON
function ToNativeFunction(cx: PJSContext): PJSFunction;
Attemps to convert the value into a native function pointer
function ToNativeFunctionName(cx: PJSContext): RawUTF8;
Attemps to convert the value into a native function name
function ToSynUnicode(cx: PJSContext): SynUnicode; overload;
Return the value as an Unicode String
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
function ToUTF8(cx: PJSContext): RawUTF8;
Return the value as an UTF-8 String
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
function ToVariant(cx: PJSContext): Variant; overload;
Return the value as variant (not implemented yet)
- will return any JavaScript string value directly as a RawUTF8
- will return any JavaScript object value as a TDocVariant
document
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
function ToWideString(cx: PJSContext): WideString;
Return the value as an Unicode WideString
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
function TransformToSynUnicode(cx: PJSContext): SynUnicode;
Transform a JSValue to its UTF-16 string representation
- JavaScript equivalent is
variable.toString()
function TransformToUTF8(cx: PJSContext): RawUTF8;
Transform a JSValue to its UTF-8 string representation
- JavaScript equivalent is
variable.toString()
function ValType(cx: PJSContext): JSType;
Type of the value
- you should better use this before calling other To*() methods
procedure AddJSON(cx: PJSContext; W: TTextWriter);
Add the value as UTF-8 encoded JSON
procedure SetAnsiChar(cx: PJSContext; Text: PAnsiChar; TextLen, CodePage: integer);
Set the value as an Ansi encoded buffer (may be UTF-8 or any code page)
- if CodePage is 0, will use the CurrentAnsiCodePage value
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
- warning - JSString
string is a subject for GC so you must root it or set as property of some object or use SetNativeString
() method to pass the value by reference
procedure SetBoolean(const Value: boolean);
Set the value as boolean
procedure SetDateTime(cx: PJSContext; const Value: TDateTime);
Set the value as a date/time
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
procedure SetDouble(const Value: double);
Set the value as floating point
procedure SetInt64(const Value: int64);
Set the value as one 64 bit integer
- this is a somewhat dirty hack, since SpiderMonkey don't support int64: but it is possible to transform int64 to double for ant value < (1 shl 51)
- sometimes we need int64 to be passed do SpiderMonkey (e.g. for an ID)
procedure SetInteger(const Value: integer);
Set the value as one 32 bit integer
procedure SetNativeString(cx: PJSContext; const aStr: SynUnicode);
Set the value as Unicode String by reference
- this is the fastest way to add a string to SpiderMonley: String is in fact not copied to the SpiderMonkey engine, just passed by reference
- Only SynUnicode
string support by now (SpiderMonkey is internally UTF-16 based)
- WARNING - as a consequence, aStr must be UNCHANGED until SpiderMonkey engine points to it (SpiderMonkey will also consider its strings as immutable, so will never change its content during execution) - for instance, never pass a function result as aStr, nor use a local SynUnicode
variable unless you trigger the Garbage Collection before the end of the local method
procedure SetNull;
Set the value as NULL
procedure SetSynUnicode(cx: PJSContext; const aStr: SynUnicode);
Set the value as an Unicode String
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
- warning - JSString
string is a subject for GC so you must root it or set as property of some object or use SetNativeString
() method to pass the value by reference
procedure SetTVarRec(cx: PJSContext; const V: TVarRec);
Set the value as TVarRec (i.e. an "array of const" open parameter)
- here any AnsiString parameter is expected to be a RawUTF8
before Delphi 2009, or its correct code page will be retrieved since Delphi 2009
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
procedure SetUTF8(cx: PJSContext; const aStr: RawUTF8);
Set the value as an UTF-8 String
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
- warning - JSString
string is a subject for GC so you must root it or set as property of some object or use SetNativeString
() method to pass the value by reference
procedure SetVariant(cx: PJSContext; const Value: Variant);
Set the value as variant (not implemented yet)
- will set any custom variant type (e.g. TDocVariant
) as a JavaScript object value computed from the JSON serialization of the variant
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
procedure SetVoid;
Set the value as VOID
procedure SetWideChar(cx: PJSContext; Text: PWideChar; TextLen: integer);
Set the value as an UTF-16 encoded buffer
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
- warning - JSString
string is a subject for GC so you must root it or set as property of some object or use SetNativeString
() method to pass the value by reference
procedure SetWideString(cx: PJSContext; const aStr: WideString);
Set the value as an Unicode WideString
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
- warning - JSString
string is a subject for GC so you must root it or set as property of some object or use SetNativeString
() method to pass the value by reference
procedure ToSynUnicode(cx: PJSContext; var result: SynUnicode); overload;
Return the value as an Unicode String
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
procedure ToVariant(cx: PJSContext; var result: Variant); overload;
Return the value as variant (not implemented yet)
- will return any JavaScript string value directly as a RawUTF8
- will return any JavaScript object value as a TDocVariant
document
- in SpiderMonkey non-simple type instances do exist in a given JSContext
, so we need to know the execution context (using a property is not an option)
property AsBoolean: boolean read ToBoolean write SetBoolean;
Access to the value as boolean
property AsDouble: double read ToDouble write SetDouble;
Access to the value as floating point
property AsInt64: int64 read ToInt64 write SetInt64;
Access to the value as one 64 bit integer
property AsInteger: integer read ToInteger write SetInteger;
Access to the value as integer
property AsJSVal: jsval read FValue write FValue;
Direct access to the internal jsval
instance
TSMObject = object(TObject)
Just a wrapper around JavaScript Object API type, to be used with other values wrappers
- SpiderMonkey object type can NOT be directly casted to this type via TSMObject
(jsobject
) - use JSObject
wrapper instead - since we expects an execution context to be specified
- to create instance of this structure, use TSMEngine.NewObject
() or MakeObject() overloaded methods
function AsSMValue: TSMValue;
Returns the associated jsobject
instance as a jsvalue
function DefineNativeMethod(const methodName: SynUnicode; func: JSNative; nargs: uintN; attrs: TJSPropertyAttrs): PJSFunction; overload;
Add JSNative
compatible function into JS object
- here the method name is specified as SynUnicode
- func if reference to function with JSNative
signature
- nargs is function argument count
- actually this method creates a JSFunction and assing its value to
obj[methodName]
- to add a global function, define it into the "global" object - i.e. call
TSMEngine.GlobalObject.DefineNativeMethod()
- this method will allow to set custom properties
attributes of this engine
function DefineNativeMethod(const methodName: SynUnicode; func: JSNative; nargs: uintN): PJSFunction; overload;
Add JSNative
compatible function into JS object
- here the method name is specified as SynUnicode
- func if reference to function with JSNative
signature
- nargs is function argument count
- actually this method creates a JSFunction and assing its value to
obj[methodName]
- to add a global function, define it into the "global" object - i.e. call
TSMEngine.GlobalObject.DefineNativeMethod()
- this method will use the default properties
attributes of this engine
function DefineNativeMethod(const methodName: AnsiString; func: JSNative; nargs: uintN; attrs: TJSPropertyAttrs): PJSFunction; overload;
Add JSNative
compatible function into JS object
- here the method name is specified as AnsiString
- func if reference to function with JSNative
signature
- nargs is function argument count
- this method will allow to set custom properties
attributes of this engine
function DefineNativeMethod(const methodName: AnsiString; func: JSNative; nargs: uintN): PJSFunction; overload;
Add JSNative
compatible function into JS object
- here the method name is specified as AnsiString
- func if reference to function with JSNative
signature
- nargs is function argument count
- this method will use the default properties
attributes of this engine
function Engine: TSMEngine;
Returns the associated script engine
instance
function GetPrivateData(expectedClass: PJSClass): pointer;
Retrieve the private data associated with an object, if that object is an instance of a specified class
- wrapper to JS_GetInstancePrivate
()
function GetPropValue(const propName: SynUnicode): TSMValue;
Get object property value (call geter for native)
- JavaScript equivalent of
obj[name]
- returns JSVAL_VOID
if object does not have such property
function GetPropVariant(const propName: SynUnicode): variant;
Get object property value (call geter for native)
- you can also use the property Properties
[]
- JavaScript equivalent of
obj[name]
- returns null
if object does not have such property
function HasOwnProperty(const propName: SynUnicode): Boolean;
Determine whether a property is physically present on a object
- JavaScript equivalent of
Object.hasOwnProperty(propName)
function HasProperty(const propName: SynUnicode): Boolean;
Check object property does exist (including prototype
chain lookup)
function IsArray: boolean;
Return TRUE if the object is an array
function ItemsCount: cardinal;
Return the number of elements in this array
function Parent: TSMObject;
Get the parent
object of a given object
function Prototype: TSMObject;
Get the prototype
of a given object
function Run(const methodName: AnsiString; const argv: array of variant): variant;
Executes a JavaScript object method using a Delphi array of variants
- returns the function result as a variant
- JavaScript equivalent of
rval := obj.methodName(argv[0], ....);
procedure Clear;
Set properties
obj
and cx to nil
procedure DefineProperty(const name: SynUnicode; const value: TSMValue); overload;
Define an object property with a value, specified as jsvalue
- this is not a direct JavaScript equivalent of
obj[name] = val
since any setter will be called
- to set a property in a global object, call either
SMEngine.Global.property := ... // via late-binding SMEngine.GlobalObject.DefineProperty() // direct via TSMObject
equivalent in JavaScript to:
var name = value
outside a JavaScript function context (i.e. in global scope)
- if property already exists, it will just replace its value with the supplied value
- this method will use the default properties
attributes of this engine
procedure DefineProperty(const name: SynUnicode; const value: variant); overload;
Define an object property with a value, specified as variant
- you can also use the property Properties
[]
- this is not a direct JavaScript equivalent of
obj[name] = val
since any setter will be called
- to set a property in a global object, call either
SMEngine.Global.property := ... // via late-binding SMEngine.GlobalObject.DefineProperty() // direct via TSMObject
equivalent in JavaScript to:
var name = value
outside a JavaScript function context (i.e. in global scope)
- if property already exists, it will just replace its value with the supplied value
- this method will use the default properties
attributes of this engine
procedure DefineProperty(const name: SynUnicode; const value: variant; attrs: TJSPropertyAttrs); overload;
Define an object property with a value, specified as variant
- you can also use the property Properties
[]
- this is not a direct JavaScript equivalent of
obj[name] = val
since any setter will be called
- to set a property in a global object, call either
SMEngine.Global.property := ... // via late-binding SMEngine.GlobalObject.DefineProperty() // direct via TSMObject
equivalent in JavaScript to:
var name = value
outside a JavaScript function context (i.e. in global scope)
- if property already exists, it will just replace its value with the supplied value
- this method will allow to set custom properties
attributes of this engine
procedure DefineProperty(const name: SynUnicode; const value: TSMValue; attrs: TJSPropertyAttrs); overload;
Define an object property with a value, specified as jsvalue
- this is not a direct JavaScript equivalent of
obj[name] = val
since any setter will be called
- to set a property in a global object, call either
SMEngine.Global.property := ... // via late-binding SMEngine.GlobalObject.DefineProperty() // direct via TSMObject
equivalent in JavaScript to:
var name = value
outside a JavaScript function context (i.e. in global scope)
- if property already exists, it will just replace its value with the supplied value
- this method will allow to set custom properties
attributes of this engine
procedure DeleteItem(aIndex: integer);
Delete an item of this object as array
procedure Evaluate(const script: SynUnicode; const scriptName: RawUTF8; lineNo: Cardinal; out result: TSMValue);
Evaluate
JavaScript script in the current object scope
- if exception raised in script - raise Delphi ESMException
- on success, returns the last executed expression statement processed in the script in low-level result output variable
- JavaScript Equivalent of
with(obj) eval(script)
- be careful about execution scope - see JS_ExecuteScript
() description
- usualy you need to evaluate
script only in global object scope, so you should better always call TSMEngine.Evaluate
()
procedure Root;
Protect the object from Garbage Collection
- if this object is not set as property value of any other object or passed as parameter to function, you must protect it
procedure RunMethod(const methodName: AnsiString; const argv: SMValArray; out rval: TSMValue); overload;
Executes a JavaScript object method using low-level SMVal arguments
- returns the function result as a TSMValue
- JavaScript equivalent of
rval := obj.methodName(argv[0], ....);
procedure RunMethod(const methodName: AnsiString; const argv: array of const; out rval: TSMValue); overload;
Executes a JavaScript object method using a Delphi array of const
- returns the function result as a TSMValue
- JavaScript equivalent of
rval := obj.methodName(argv[0], ....);
- here any AnsiString parameter is expected to be a RawUTF8
before Delphi 2009, or its correct code page will be retrieved since Delphi 2009
procedure UnRoot;
Unprotect a previously "rooted" object
- WARNING!! Object MUST be protected by a previous Root
method call, otherwise you get an access violation
property cx: PJSContext read fCx;
Returns the associated execution context
property DefaultPropertyAttrs: TJSPropertyAttrs read FDefaultPropertyAttrs write SetDefaultPropertyAttrs;
Access to the default attributes when accessing any properties
property Items[aIndex: integer]: variant read GetItem write SetItem;
Access to an item of this object as array
property obj: PJSObject read fObj;
Returns the associated jsobject
instance
property PrivateData: pointer read GetPrivate write SetPrivate;
Access the private data field of an object
- wrapper to JS_GetPrivate
()/JS_SetPrivate
()
- only works if the object's JSClass
has the JSCLASS_HAS_PRIVATE
flag: it is safer to use GetPrivateData
() method and providing the JSClass
property Properties[const propName: SynUnicode]: variant read GetPropVariant write SetPropVariant;
Read/write access to the object properties
as variant
TSMEngineMethodEvent = record
Used to store one registered method event
TSMEngine = class(TObject)
Implements a ThreadSafe JavaScript engine
- use TSMEngineManager.ThreadSafeEngine
to retrieve the Engine instance corresponding to the current thread, in multithread application
- contains JSRuntime
+ JSContext
(to be ready for new SpiderMonkey version where context and runtime is the same)
- contains also one "global" JavaScript object. From script it is accessible via "global." (in browser, this is the "window." object)
- set SpiderMonkey error reporter and store last SpiderMonkey error in LastError property
constructor Create(aManager: TSMEngineManager); virtual;
Create
one threadsafe JavaScript Engine instance
- initialize internal JSRuntime
, JSContext
, and global
objects and standard JavaScript classes
- do not create
Engine directly via this constructor, but instead call TSMEngineManager.ThreadSafeEngine
destructor Destroy; override;
Finalize the JavaScript engine instance
function Evaluate(const script: SynUnicode; const scriptName: RawUTF8='script'; lineNo: Cardinal=1): variant;
Evaluate
a JavaScript script in the global
scope
- a wrapper to GlobalObject.Evaluate(...)
- if exception raised in script - raise Delphi ESMException
- on success returns last executed expression statement processed in the script as a variant
- JavaScript equivalent to
eval(script)
function NewSMVariant: variant;
Create
new ordinary JavaScript object, stored as TSMVariant
custom type
- JavaScript equivalent of
{}
- new object is subject to Garbage Collection, so should be assigned as value for a property to create
new object type property, as in JavaScript:
var obj = {}
function RegisterMethod(obj: PJSObject; const MethodName: SynUnicode; const Event: TSMEngineMethodEventJSON; ArgumentsCount: integer): PJSFunction; overload;
Register a native Delphi JSON-based method for a given object
- the supplied function name is case-sensitive
- the supplied callback will be executed directly by the JavaScript engine, supplying all parameters as JSON array, and returning the function result either as a JSON value or a JSON object
- raise an ESMException
if the function could not be registered
function RegisterMethod(obj: PJSObject; const MethodName: SynUnicode; const Event: TSMEngineMethodEventVariant; ArgumentsCount: integer): PJSFunction; overload;
Register a native Delphi variant-based method for a given object
- the supplied function name is case-sensitive
- the supplied callback will be executed directly by the JavaScript engine, supplying all parameters as variant (including TDocVariant
for any complex object), and returning the function result as variant
- raise an ESMException
if the function could not be registered
procedure CheckJSError(res: JSBool); virtual;
Check if last call to JSAPI compile/eval fucntion was successful
- raise ESMException
if any error occurred
- put error description to SynSMLog
procedure ClearLastError;
Clear last JavaScript error
- called before every evaluate
() function call
procedure GarbageCollect;
Trigger Garbage Collection
- all unrooted things (JSString
, JSObject
, VSVal) will be released
procedure InitClass(clasp: PJSClass; ps: PJSPropertySpec; var newobj: TSMObject);
Create
new JavaScript object from its class and property specifications
procedure MakeObject(const value: TSMValue; out obj: TSMObject); overload;
Converts a JavaScript value into a JavaScript object
procedure MakeObject(const value: jsval; out obj: TSMObject); overload;
Converts a JavaScript low-level value into a JavaScript object
procedure MakeObject(jsobj: PJSObject; out obj: TSMObject); overload;
Converts a JavaScript low-level object into a JavaScript object
procedure MaybeGarbageCollect;
Offer the JavaScript engine an opportunity to perform garbage collection if needed
- Tries to determine whether garbage collection in would free up enough memory to be worth the amount of time it would take. If so, it performs some garbage collection
- Frequent calls are safe and will not cause the application to spend a lot of time doing redundant garbage collection work
procedure NewObject(const prototype: TSMObject; out newobj: TSMObject); overload;
Create
new JavaScript object with prototype
- JavaScript equivalent of
{}.__proto__ := prototype;
procedure NewObject(out newobj: TSMObject); overload;
Create
new ordinary JavaScript object
- JavaScript equivalent of
{}
- new object is subject to Garbage Collection, so must be rooted or assigned as value for a property to create
new object type property, as in JavaScript:
var obj = {}
procedure NewObjectWithClass(clasp: PJSClass; const prototype: TSMObject; const parent: TSMObject; var newobj: TSMObject); overload;
Create
new JavaScript object from its prototype
procedure NewObjectWithClass(clasp: PJSClass; var newobj: TSMObject); overload;
Create
new JavaScript object from its class
procedure NewSMVariantRooted(out newobj: variant);
Create
new ordinary JavaScript object, stored as TSMVariant
custom type, and rooted to avoid garbage collection
- JavaScript equivalent of
{}
- new object is subject to Garbage Collection, so is rooted and should be explicitly unrooted, e.g. via:
obj: variant; ... FManager.ThreadSafeEngine.NewSMVariantRooted(obj); try ... work with obj finally obj._UnRoot; // pseudo-method end;
procedure UnRegisterMethod(JSFunction: PJSFunction);
Unregister a native Delphi method for a given object
- raise an ESMException
if the function was not previously registered
- you should not call it usually, but it is available in case
property comp: PJSCompartment read fcomp;
Access to the associated execution compartment
property cx: PJSContext read fCx;
Access to the associated execution context
property DefaultPropertyAttrs: TJSPropertyAttrs read FDefaultPropertyAttrs write SetDefaultPropertyAttrs;
Access to the default attributes when accessing any properties
property EngineContentVersion: Cardinal read FEngineContentVersion;
Internal version number of engine scripts
- used in TSMEngine.ThreadSafeEngine to determine if context is up to date, in order to trigger on-the-fly reload of scripts without the need if restarting the application
- caller must change this parameter value e.g. in case of changes in the scripts folder in an HTTP server
property ErrorExist: boolean read FErrorExist;
TRUE if an error was triggered during JavaScript execution
property Global: variant read FGlobal;
Access to the associated global
object as a TSMVariant
custom variant
- allows direct property and method executions in Delphi code, via late-binding, for instance:
engine.Global.MyVariable := 1.0594631; engine.Global.MyFunction(1,'text');
property GlobalObj: PJSObject read FGlobalObject.fobj;
Access to the associated global
object as low-level PJSObject
property GlobalObject: TSMObject read FGlobalObject;
Access to the associated global
object as a TSMObject
wrapper
- you can use it to register a method
property LastErrorFileName: RawUTF8 read FLastErrorFileName;
Last error file name triggered during JavaScript execution
property LastErrorLine: integer read FLastErrorLine;
Last error source code line number triggered during JavaScript execution
property LastErrorMsg: RawUTF8 read FLastErrorMsg;
Last error message triggered during JavaScript execution
property rt: PJSRuntime read frt;
Access to the associated execution runtime
property TimeOutAborted: boolean read FTimeOutAborted;
Notifies a WatchDog timeout
property TimeOutValue: Double read fTimeoutInterval write SetTimeoutValue;
Define a WatchDog timeout interval
- is set to -1 by default, i.e. meaning no execution timeout
TSMEngineManager = class(TObject)
Main access point to the SpiderMonkey per-thread scripting engines
- allow thread-safe access to an internal per-thread TSMEngine
instance list
- contains runtime-level properties shared between thread-safe engines
- you can create several TSMEngineManager
instances, if you need several separate scripting instances
- set OnNewEngine callback to initialize each TSMEngine
, when a new thread is accessed, and tune per-engine memory allocation via MaxPerEngineMemory and MaxRecursionDepth
- get the current per-thread TSMEngine
instance via ThreadSafeEngine method
constructor Create; virtual;
Initialize the SpiderMonkey scripting engine
destructor Destroy; override;
Finalize the SpiderMonkey scripting engine
function ThreadSafeEngine: TSMEngine;
Get or create
one Engine associated with current running thread
- in single thread application will return the MainEngine
procedure ReleaseCurrentThreadEngine;
Method to be called when a thread is about to be finished
- you can call this method just before a thread is finished to ensure that the associated scripting Engine will be released
- could be used e.g. in a try...finally block inside a TThread.Execute overriden method
property ContentVersion: Cardinal read FContentVersion write FContentVersion;
Internal version of the script files
- used in TSMEngine.ThreadSafeEngine to determine if context is up to date, in order to trigger on-the-fly reload of scripts without the need if restarting the application
property Lock: TRTLCriticalSection read FEngineCS;
Lock
/mutex used for thread-safe access to the TSMEngine
list
property MaxPerEngineMemory: Cardinal read FMaxPerEngineMemory write SetMaxPerEngineMemory default 8*1024*1024;
Max amount of memory (in bytes) for a single SpiderMonkey instance
- this parameter will be set only at Engine start, i.e. it must be set BEFORE any call to ThreadSafeEngine
- default is 8 MB
property MaxRecursionDepth: Cardinal read FMaxRecursionDepth write FMaxRecursionDepth default 32;
Maximum expected recursion depth for JavaScript functions
- to avoid out of memory situation in functions like
function f(){ f() };
- default is 32, but you can specify some higher value
property OnNewEngine: TEngineEvent read FOnNewEngine write FOnNewEngine;
Event triggered every time a new Engine is created
- here your code can change the initial state of the Engine
TSMVariant = class(TSynInvokeableVariantType)
A custom variant type used to store a SpiderMonkey object in Delphi code
- via the magic of late binding, it will allow access of any JavaScript object property, or execute any of its methods
- primitive types (i.e. null
, string, or numbers) will be stored as simple variant instances, but JavaScript objects (i.e. objects, prototypes or functions) can be stored as an instance of this TSMVariant
custom type
- you can use the _Root and _UnRoot pseudo-methods, which will protect the object instance to avoid unexpected Garbage Collection
function DoFunction(var Dest: TVarData; const V: TVarData; const Name: string; const Arguments: TVarDataArray): Boolean; override;
Low-level callback to execute any JavaScript object method
- add the _(Index: integer): variant method to retrieve an item if the object is an array
procedure Cast(var Dest: TVarData; const Source: TVarData); override;
Handle type conversion
- any TSMVariant
will be converted to '<<JavaScript TSMVariant
>>' text
procedure CastTo(var Dest: TVarData; const Source: TVarData; const AVarType: TVarType); override;
Handle type conversion
- any TSMVariant
will be converted to '<<JavaScript TSMVariant
>>' text
class procedure New(const aObject: TSMObject; out aValue: variant); overload;
Initialize a variant instance to store a JavaScript object
class procedure New(cx: PJSContext; obj: PJSObject; out aValue: variant); overload;
Initialize a variant instance to store a JavaScript object
class procedure New(engine: TSMEngine; out aValue: variant); overload;
Initialize a variant instance to store a new
JavaScript object
procedure ToJSON(W: TTextWriter; const Value: variant; Escape: TTextWriterKind); override;
This implementation will let SpiderMonkey write directly the JSON content
TSMVariantData = object(TObject)
Memory structure used for TSMVariant
storage of any JavaScript object as Delphi variant
- primitive types (i.e. null
, string, or numbers) will be stored as simple variant instances, but JavaScript objects (i.e. objects, prototypes or functions) can be stored as an instance of this TSMVariant
custom type
- this variant stores its execution context, so is pretty convenient to work with in plain Delphi code, also thanks to late-binding feature
procedure GetGlobal(out global: variant);
Retrieve the global object of this execution context
- you can use this from a native function, e.g.:
function TMyClass.MyFunction(const This: variant; const Args: array of variant): variant; var global: variant; begin TSMVariantData(This).GetGlobal(global); global.anotherFunction(Args[0],Args[1],'test'); // same as: global := TSMVariantData(This).SMObject.Engine.Global; global.anotherFunction(Args[0],Args[1],'test'); // but you may also write directly: with TSMVariantData(This).SMObject.Engine do Global.anotherFunction(Args[0],Args[1],'test'); result := AnyTextFileToSynUnicode(Args[0]); end;
procedure Init(aCx: PJSContext; aObj: PJSObject); overload;
Initialize a TSMVariant
structure to store a specified JavaScript object
procedure Init(const aObject: TSMObject); overload;
Initialize a TSMVariant
structure to store a specified JavaScript object
procedure InitNew(engine: TSMEngine);
Initialize a TSMVariant
structure to store a new JavaScript object
property cx: PJSContext read VObject.fcx;
Returns the associated execution context
property obj: PJSObject read VObject.fobj;
Returns the associated jsobject
instance
property SMObject: TSMObject read VObject;
Returns the associated TSMObject
instance
property VarType: word read VType;
Return the custom variant type identifier, i.e. SMVariantType.VarType
PSMObject = ^TSMObject;
Pointer to our wrapper around JavaScript Object
PSMValue = ^TSMValue;
A pointer to a jsval
wrapper
PSMValues = ^TSMValues;
A pointer to a jsval
wrappers array
PSMVariantData = ^TSMVariantData;
Pointer to a TSMVariant
storage
SMValArray = array of TSMValue;
A dynamic array of jsval
wrappers
TEngineEvent = procedure(const Engine: TSMEngine) of object;
Prototype of SpideMonkey notification callback method
TSMEngineMethodEventDynArray = array of TSMEngineMethodEvent;
Used to store the registered method events
TSMEngineMethodEventJSON = function(const This: TSMObject; const Args: RawUTF8): RawUTF8 of object;
/ JSON-based callback signature used for TSMEngine.RegisterMethod
()
- any Delphi exception raised during this execution will be converted into a JavaScript exception by TSMEngine
- similar to TServiceMethod.InternalExecute() as defined in mORMot
(for instance, this callback will be used to execute native Delphi interface-based methods from JavaScript code in mORMotSM.pas unit)
- "this" JavaScript calling object is transmitted as low-level TSMObject
- will expect as input a JSON array of parameters from Args, e.g.
'[1,2,3]'
- if the method only expect one result, shall return one JSON value, e.g.
'6'
- if the method expect more than one result (i.e. several var/out parameters in addition to the main function result), it shall return a JSON object, with parameter names for all var/out/result values, e.g.
'{"first":1,"second":2,"result":3}'
- this allows the function result to be consumed by the JavaScript as a regular JS value or object
- corresponds to meJSON kind of callback method
TSMEngineMethodEventKind = ( meVariant, meJSON );
Kinds of callback methods available for TSMEngine.RegisterMethod
()
TSMEngineMethodEventVariant = function(const This: variant; const Args: array of variant): variant of object;
/ variant-based callback signature used for TSMEngine.RegisterMethod
()
- any Delphi exception raised during this execution will be converted into a JavaScript exception by TSMEngine
- "this" JavaScript calling object is transmitted as a TSMVariant
custom variant: you can use late-binding over it to access its methods or properties, or transtype it using TSMVariantData
(Instance) and access its low-level API content
- input arguments (and function result) are simple variant values, or TDocVariant
custom variant instance for any object as complex document
- corresponds to meVariant kind of callback method
TSMValues = array[0..(MaxInt div sizeof(TSMValue))-1] of TSMValue;
A jsval
wrappers array
STACK_CHUNK_SIZE: cardinal = 8192;
Default stack growing size, in bytes
Functions or procedures | Description | |
---|---|---|
JSError | To be used to catch Delphi exceptions inside JSNative function implementation | |
VariantToJSVal | Convert a variant to a Java Script value |
procedure JSError(cx: PJSContext; aException: Exception; const aContext: RawByteString='');
To be used to catch Delphi exceptions inside JSNative
function implementation
- usage example:
try doSomething() Result := JS_TRUE; except on E: Exception do begin JS_SET_RVAL(cx, vp, JSVAL_VOID); JSError(cx, E); Result := JS_FALSE; end;
function VariantToJSVal(cx: PJSContext; const Value: Variant): jsval;
Convert a variant to a Java Script value
SMVariantType: TSynInvokeableVariantType = nil;
The internal custom variant type used to register TSMVariant
SynSMLog: TSynLogClass=TSynLog;
Define the TSynLog
class used for logging for all our SynSM
related units
- you may override it with TSQLLog
, if available from mORMot
- since not all exceptions are handled specificaly by this unit, you may better use a common TSynLog
class for the whole application or module