Repository: tondrej/chakracore-delphi Branch: master Commit: e01131b55694 Files: 77 Total size: 779.4 KB Directory structure: gitextract_l0pubcul/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── include/ │ ├── ChakraCommon.h │ ├── ChakraCore.h │ ├── ChakraCoreVersion.h │ └── ChakraDebug.h ├── packages.config ├── samples/ │ ├── HostSample/ │ │ ├── ChakraCoreHostMainData.dfm │ │ ├── ChakraCoreHostMainData.pas │ │ ├── ChakraCoreHostSample.XE.dproj │ │ ├── ChakraCoreHostSample.dof │ │ ├── ChakraCoreHostSample.dpr │ │ ├── ChakraCoreHostSample.lpi │ │ ├── ChakraCoreHostSample.res │ │ ├── Console.pas │ │ └── scripts/ │ │ ├── json2.js │ │ └── main.js │ ├── NodeSample/ │ │ ├── EventEmitter.pas │ │ ├── NodeMainData.dfm │ │ ├── NodeMainData.pas │ │ ├── NodeProcess.pas │ │ ├── NodeSample.XE.dproj │ │ ├── NodeSample.dof │ │ ├── NodeSample.dpr │ │ ├── NodeSample.lpi │ │ ├── NodeSample.res │ │ ├── README.md │ │ ├── demo_commonmark.js │ │ ├── demo_graphql.js │ │ ├── demo_json-query.js │ │ ├── demo_lodash.js │ │ └── demo_moment.js │ ├── Samples.XE.groupproj │ ├── Samples.bpg │ ├── Samples.lpg │ ├── SimpleHostSample/ │ │ ├── SimpleHost.XE.dproj │ │ ├── SimpleHost.dof │ │ ├── SimpleHost.dpr │ │ ├── SimpleHost.lpi │ │ ├── SimpleHost.res │ │ └── scripts/ │ │ └── hello.js │ └── WasmSample/ │ ├── README.md │ ├── WasmMainData.dfm │ ├── WasmMainData.pas │ ├── WasmMainForm.dfm │ ├── WasmMainForm.pas │ ├── WasmSample.XE.dproj │ ├── WasmSample.dof │ ├── WasmSample.dpr │ ├── WasmSample.lpi │ ├── WasmSample.res │ └── scripts/ │ ├── main.js │ └── main.wasm ├── src/ │ ├── ChakraCommon.pas │ ├── ChakraCore.pas │ ├── ChakraCoreClasses.pas │ ├── ChakraCoreUtils.pas │ ├── ChakraCoreVersion.pas │ ├── ChakraDebug.pas │ ├── Compat.pas │ └── common.inc └── tests/ ├── ChakraCoreTests.XE.dproj ├── ChakraCoreTests.dof ├── ChakraCoreTests.dpr ├── ChakraCoreTests.lpi ├── ChakraCoreTests.res ├── ChakraCoreTestsUI.XE.dproj ├── ChakraCoreTestsUI.dof ├── ChakraCoreTestsUI.dpr ├── ChakraCoreTestsUI.lpi ├── ChakraCoreTestsUI.res ├── Test_ChakraCore.pas ├── Test_Classes.pas └── tests.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ github: tondrej ================================================ FILE: .gitignore ================================================ # Uncomment these types if you want even more clean repository. But be careful. # It can make harm to an existing project source. Read explanations below. # # Resource files are binaries containing manifest, project icon and version info. # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. #*.res # # Type library file (binary). In old Delphi versions it should be stored. # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. #*.tlb # # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. # Uncomment this if you are not using diagrams or use newer Delphi version. #*.ddp # # Visual LiveBindings file. Added in Delphi XE2. # Uncomment this if you are not using LiveBindings Designer. #*.vlb # # Deployment Manager configuration file for your project. Added in Delphi XE2. # Uncomment this if it is not mobile development and you do not use remote debug feature. #*.deployproj # # C++ object files produced when C/C++ Output file generation is configured. # Uncomment this if you are not using external objects (zlib library for example). #*.obj # # Delphi compiler-generated binaries (safe to delete) *.exe *.dll *.bpl *.bpi *.dcp *.so *.apk *.drc *.map *.dres *.rsm *.tds *.dcu *.lib *.a *.o *.ocx *.otares # Delphi autogenerated files (duplicated info) *.cfg *.ddp *.hpp *Resource.rc # Delphi local files (user-specific info) *.local *.identcache *.projdata *.tvsconfig *.dsk # Delphi history and backups __history/ __recovery/ *.~* # Castalia statistics file (since XE7 Castalia is distributed with Delphi) *.stat # FPC local files (user-specific info) *.lps # chakracore-delphi-specific paths /bin /lib ================================================ FILE: .gitmodules ================================================ [submodule "ext/jedi"] path = ext/jedi url = https://github.com/tondrej/jedi ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # chakracore-delphi [![Licensed under the MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/tondrej/chakracore-delphi/blob/master/LICENSE) ![PR's Welcome](https://img.shields.io/badge/PRs%20-welcome-brightgreen.svg) [Delphi](https://www.embarcadero.com/products/delphi) and [Free Pascal](https://www.freepascal.org) bindings and classes for Microsoft's [ChakraCore](https://github.com/Microsoft/ChakraCore) library. ChakraCore version: **1.11.24** Supported compilers: - Delphi 7 or newer - Free Pascal 3.0.4 or newer Supported target platforms: - i386-win32 (Delphi 7 or newer, Free Pascal) - x86_64-win64 (Delphi XE2 or newer, Free Pascal) - x86_64-linux (Free Pascal) - x86_64-darwin (Free Pascal) Installation: 1. Clone this repository: ```bash git clone https://github.com/tondrej/chakracore-delphi.git cd chakracore-delphi git submodule update --init ``` or ```bash git clone --recurse-submodules https://github.com/tondrej/chakracore-delphi.git ``` 2. Download the binaries from the ChakraCore [Release](https://github.com/Microsoft/ChakraCore/releases/tag/v1.11.24) page 3. Enjoy! ================================================ FILE: include/ChakraCommon.h ================================================ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to host Chakra. /// /// This file contains the common API set shared among all Chakra releases. For Windows-specific /// releases, see chakrart.h. /// \file /// \brief The base Chakra hosting API. /// /// This file contains a flat C API layer. This is the API exported by chakra.dll. #ifdef _MSC_VER #pragma once #endif // _MSC_VER #ifndef _CHAKRACOMMON_H_ #define _CHAKRACOMMON_H_ // Platform specific code #if defined(_WIN32) && defined(_MSC_VER) #include // Header macros #define CHAKRA_CALLBACK CALLBACK #define CHAKRA_API STDAPI_(JsErrorCode) typedef DWORD_PTR ChakraCookie; typedef BYTE* ChakraBytePtr; #else // Non-Windows VC++ // SAL compat #define _Return_type_success_(x) #define _In_ #define _In_z_ #define _In_opt_ #define _Inout_ #define _Out_ #define _Out_opt_ #define _In_reads_(x) #define _Pre_maybenull_ #define _Pre_writable_byte_size_(byteLength) #define _Outptr_result_buffer_(byteLength) #define _Outptr_result_bytebuffer_(byteLength) #define _Outptr_result_maybenull_ #define _Outptr_result_z_ #define _Ret_maybenull_ #define _Out_writes_(size) #define _Out_writes_to_opt_(byteLength, byteLength2) // Header macros #ifdef __i386___ #define CHAKRA_CALLBACK __attribute__((cdecl)) #else // non-32 bit x86 doesn't have cdecl support #define CHAKRA_CALLBACK #endif // __i386__ #ifndef _WIN32 #define SET_API_VISIBILITY __attribute__((visibility("default"))) #else #define SET_API_VISIBILITY #endif #ifdef __cplusplus #define CHAKRA_API extern "C" SET_API_VISIBILITY JsErrorCode #else #define CHAKRA_API extern SET_API_VISIBILITY JsErrorCode #include #endif #include // for size_t #include // for uintptr_t typedef uintptr_t ChakraCookie; typedef unsigned char* ChakraBytePtr; // xplat-todo: try reduce usage of following types #if !defined(__MSTYPES_DEFINED) typedef uint32_t UINT32; typedef int64_t INT64; typedef void* HANDLE; typedef unsigned char BYTE; typedef BYTE byte; typedef UINT32 DWORD; typedef unsigned short WCHAR; #endif #endif // defined(_WIN32) && defined(_MSC_VER) #if (defined(_MSC_VER) && _MSC_VER <= 1900) || (!defined(_MSC_VER) && __cplusplus <= 199711L) // !C++11 typedef unsigned short uint16_t; #else #include #endif /// /// An error code returned from a Chakra hosting API. /// typedef _Return_type_success_(return == 0) enum _JsErrorCode { /// /// Success error code. /// JsNoError = 0, /// /// Category of errors that relates to incorrect usage of the API itself. /// JsErrorCategoryUsage = 0x10000, /// /// An argument to a hosting API was invalid. /// JsErrorInvalidArgument, /// /// An argument to a hosting API was null in a context where null is not allowed. /// JsErrorNullArgument, /// /// The hosting API requires that a context be current, but there is no current context. /// JsErrorNoCurrentContext, /// /// The engine is in an exception state and no APIs can be called until the exception is /// cleared. /// JsErrorInExceptionState, /// /// A hosting API is not yet implemented. /// JsErrorNotImplemented, /// /// A hosting API was called on the wrong thread. /// JsErrorWrongThread, /// /// A runtime that is still in use cannot be disposed. /// JsErrorRuntimeInUse, /// /// A bad serialized script was used, or the serialized script was serialized by a /// different version of the Chakra engine. /// JsErrorBadSerializedScript, /// /// The runtime is in a disabled state. /// JsErrorInDisabledState, /// /// Runtime does not support reliable script interruption. /// JsErrorCannotDisableExecution, /// /// A heap enumeration is currently underway in the script context. /// JsErrorHeapEnumInProgress, /// /// A hosting API that operates on object values was called with a non-object value. /// JsErrorArgumentNotObject, /// /// A script context is in the middle of a profile callback. /// JsErrorInProfileCallback, /// /// A thread service callback is currently underway. /// JsErrorInThreadServiceCallback, /// /// Scripts cannot be serialized in debug contexts. /// JsErrorCannotSerializeDebugScript, /// /// The context cannot be put into a debug state because it is already in a debug state. /// JsErrorAlreadyDebuggingContext, /// /// The context cannot start profiling because it is already profiling. /// JsErrorAlreadyProfilingContext, /// /// Idle notification given when the host did not enable idle processing. /// JsErrorIdleNotEnabled, /// /// The context did not accept the enqueue callback. /// JsCannotSetProjectionEnqueueCallback, /// /// Failed to start projection. /// JsErrorCannotStartProjection, /// /// The operation is not supported in an object before collect callback. /// JsErrorInObjectBeforeCollectCallback, /// /// Object cannot be unwrapped to IInspectable pointer. /// JsErrorObjectNotInspectable, /// /// A hosting API that operates on symbol property ids but was called with a non-symbol property id. /// The error code is returned by JsGetSymbolFromPropertyId if the function is called with non-symbol property id. /// JsErrorPropertyNotSymbol, /// /// A hosting API that operates on string property ids but was called with a non-string property id. /// The error code is returned by existing JsGetPropertyNamefromId if the function is called with non-string property id. /// JsErrorPropertyNotString, /// /// Module evaluation is called in wrong context. /// JsErrorInvalidContext, /// /// Module evaluation is called in wrong context. /// JsInvalidModuleHostInfoKind, /// /// Module was parsed already when JsParseModuleSource is called. /// JsErrorModuleParsed, /// /// Argument passed to JsCreateWeakReference is a primitive that is not managed by the GC. /// No weak reference is required, the value will never be collected. /// JsNoWeakRefRequired, /// /// The Promise object is still in the pending state. /// JsErrorPromisePending, /// /// Module was not yet evaluated when JsGetModuleNamespace was called. /// JsErrorModuleNotEvaluated, /// /// Category of errors that relates to errors occurring within the engine itself. /// JsErrorCategoryEngine = 0x20000, /// /// The Chakra engine has run out of memory. /// JsErrorOutOfMemory, /// /// The Chakra engine failed to set the Floating Point Unit state. /// JsErrorBadFPUState, /// /// Category of errors that relates to errors in a script. /// JsErrorCategoryScript = 0x30000, /// /// A JavaScript exception occurred while running a script. /// JsErrorScriptException, /// /// JavaScript failed to compile. /// JsErrorScriptCompile, /// /// A script was terminated due to a request to suspend a runtime. /// JsErrorScriptTerminated, /// /// A script was terminated because it tried to use eval or function and eval /// was disabled. /// JsErrorScriptEvalDisabled, /// /// Category of errors that are fatal and signify failure of the engine. /// JsErrorCategoryFatal = 0x40000, /// /// A fatal error in the engine has occurred. /// JsErrorFatal, /// /// A hosting API was called with object created on different javascript runtime. /// JsErrorWrongRuntime, /// /// Category of errors that are related to failures during diagnostic operations. /// JsErrorCategoryDiagError = 0x50000, /// /// The object for which the debugging API was called was not found /// JsErrorDiagAlreadyInDebugMode, /// /// The debugging API can only be called when VM is in debug mode /// JsErrorDiagNotInDebugMode, /// /// The debugging API can only be called when VM is at a break /// JsErrorDiagNotAtBreak, /// /// Debugging API was called with an invalid handle. /// JsErrorDiagInvalidHandle, /// /// The object for which the debugging API was called was not found /// JsErrorDiagObjectNotFound, /// /// VM was unable to perform the request action /// JsErrorDiagUnableToPerformAction, } JsErrorCode; /// /// A handle to a Chakra runtime. /// /// /// /// Each Chakra runtime has its own independent execution engine, JIT compiler, and garbage /// collected heap. As such, each runtime is completely isolated from other runtimes. /// /// /// Runtimes can be used on any thread, but only one thread can call into a runtime at any /// time. /// /// /// NOTE: A JsRuntimeHandle, unlike other object references in the Chakra hosting API, /// is not garbage collected since it contains the garbage collected heap itself. A runtime /// will continue to exist until JsDisposeRuntime is called. /// /// typedef void *JsRuntimeHandle; /// /// An invalid runtime handle. /// #ifdef __cplusplus const JsRuntimeHandle JS_INVALID_RUNTIME_HANDLE = 0; #else #define JS_INVALID_RUNTIME_HANDLE (JsRuntimeHandle)0 #endif /// /// A reference to an object owned by the Chakra garbage collector. /// /// /// A Chakra runtime will automatically track JsRef references as long as they are /// stored in local variables or in parameters (i.e. on the stack). Storing a JsRef /// somewhere other than on the stack requires calling JsAddRef and JsRelease to /// manage the lifetime of the object, otherwise the garbage collector may free the object /// while it is still in use. /// typedef void *JsRef; /// /// An invalid reference. /// #ifdef __cplusplus const JsRef JS_INVALID_REFERENCE = 0; #else #define JS_INVALID_REFERENCE (JsRef)0 #endif /// /// A reference to a script context. /// /// /// /// Each script context contains its own global object, distinct from the global object in /// other script contexts. /// /// /// Many Chakra hosting APIs require an "active" script context, which can be set using /// JsSetCurrentContext. Chakra hosting APIs that require a current context to be set /// will note that explicitly in their documentation. /// /// typedef JsRef JsContextRef; /// /// A reference to a JavaScript value. /// /// /// A JavaScript value is one of the following types of values: undefined, null, Boolean, /// string, number, or object. /// typedef JsRef JsValueRef; /// /// A cookie that identifies a script for debugging purposes. /// typedef ChakraCookie JsSourceContext; /// /// An empty source context. /// #ifdef __cplusplus const JsSourceContext JS_SOURCE_CONTEXT_NONE = (JsSourceContext)-1; #else #define JS_SOURCE_CONTEXT_NONE (JsSourceContext)-1 #endif /// /// A property identifier. /// /// /// Property identifiers are used to refer to properties of JavaScript objects instead of using /// strings. /// typedef JsRef JsPropertyIdRef; /// /// Attributes of a runtime. /// typedef enum _JsRuntimeAttributes { /// /// No special attributes. /// JsRuntimeAttributeNone = 0x00000000, /// /// The runtime will not do any work (such as garbage collection) on background threads. /// JsRuntimeAttributeDisableBackgroundWork = 0x00000001, /// /// The runtime should support reliable script interruption. This increases the number of /// places where the runtime will check for a script interrupt request at the cost of a /// small amount of runtime performance. /// JsRuntimeAttributeAllowScriptInterrupt = 0x00000002, /// /// Host will call JsIdle, so enable idle processing. Otherwise, the runtime will /// manage memory slightly more aggressively. /// JsRuntimeAttributeEnableIdleProcessing = 0x00000004, /// /// Runtime will not generate native code. /// JsRuntimeAttributeDisableNativeCodeGeneration = 0x00000008, /// /// Using eval or function constructor will throw an exception. /// JsRuntimeAttributeDisableEval = 0x00000010, /// /// Runtime will enable all experimental features. /// JsRuntimeAttributeEnableExperimentalFeatures = 0x00000020, /// /// Calling JsSetException will also dispatch the exception to the script debugger /// (if any) giving the debugger a chance to break on the exception. /// JsRuntimeAttributeDispatchSetExceptionsToDebugger = 0x00000040, /// /// Disable Failfast fatal error on OOM /// JsRuntimeAttributeDisableFatalOnOOM = 0x00000080, /// /// Runtime will not allocate executable code pages /// This also implies that Native Code generation will be turned off /// Note that this will break JavaScript stack decoding in tools // like WPA since they rely on allocation of unique thunks to // interpret each function and allocation of those thunks will be // disabled as well /// JsRuntimeAttributeDisableExecutablePageAllocation = 0x00000100, } JsRuntimeAttributes; /// /// The type of a typed JavaScript array. /// typedef enum _JsTypedArrayType { /// /// An int8 array. /// JsArrayTypeInt8, /// /// An uint8 array. /// JsArrayTypeUint8, /// /// An uint8 clamped array. /// JsArrayTypeUint8Clamped, /// /// An int16 array. /// JsArrayTypeInt16, /// /// An uint16 array. /// JsArrayTypeUint16, /// /// An int32 array. /// JsArrayTypeInt32, /// /// An uint32 array. /// JsArrayTypeUint32, /// /// A float32 array. /// JsArrayTypeFloat32, /// /// A float64 array. /// JsArrayTypeFloat64 } JsTypedArrayType; /// /// Allocation callback event type. /// typedef enum _JsMemoryEventType { /// /// Indicates a request for memory allocation. /// JsMemoryAllocate = 0, /// /// Indicates a memory freeing event. /// JsMemoryFree = 1, /// /// Indicates a failed allocation event. /// JsMemoryFailure = 2 } JsMemoryEventType; /// /// Attribute mask for JsParseScriptWithAttributes /// typedef enum _JsParseScriptAttributes { /// /// Default attribute /// JsParseScriptAttributeNone = 0x0, /// /// Specified script is internal and non-user code. Hidden from debugger /// JsParseScriptAttributeLibraryCode = 0x1, /// /// ChakraCore assumes ExternalArrayBuffer is Utf8 by default. /// This one needs to be set for Utf16 /// JsParseScriptAttributeArrayBufferIsUtf16Encoded = 0x2, } JsParseScriptAttributes; /// /// Type enumeration of a JavaScript property /// typedef enum _JsPropertyIdType { /// /// Type enumeration of a JavaScript string property /// JsPropertyIdTypeString, /// /// Type enumeration of a JavaScript symbol property /// JsPropertyIdTypeSymbol } JsPropertyIdType; /// /// The JavaScript type of a JsValueRef. /// typedef enum _JsValueType { /// /// The value is the undefined value. /// JsUndefined = 0, /// /// The value is the null value. /// JsNull = 1, /// /// The value is a JavaScript number value. /// JsNumber = 2, /// /// The value is a JavaScript string value. /// JsString = 3, /// /// The value is a JavaScript Boolean value. /// JsBoolean = 4, /// /// The value is a JavaScript object value. /// JsObject = 5, /// /// The value is a JavaScript function object value. /// JsFunction = 6, /// /// The value is a JavaScript error object value. /// JsError = 7, /// /// The value is a JavaScript array object value. /// JsArray = 8, /// /// The value is a JavaScript symbol value. /// JsSymbol = 9, /// /// The value is a JavaScript ArrayBuffer object value. /// JsArrayBuffer = 10, /// /// The value is a JavaScript typed array object value. /// JsTypedArray = 11, /// /// The value is a JavaScript DataView object value. /// JsDataView = 12, } JsValueType; /// /// User implemented callback routine for memory allocation events /// /// /// Use JsSetRuntimeMemoryAllocationCallback to register this callback. /// /// /// The state passed to JsSetRuntimeMemoryAllocationCallback. /// /// The type of type allocation event. /// The size of the allocation. /// /// For the JsMemoryAllocate event, returning true allows the runtime to continue /// with the allocation. Returning false indicates the allocation request is rejected. The /// return value is ignored for other allocation events. /// typedef bool (CHAKRA_CALLBACK * JsMemoryAllocationCallback)(_In_opt_ void *callbackState, _In_ JsMemoryEventType allocationEvent, _In_ size_t allocationSize); /// /// A callback called before collection. /// /// /// Use JsSetBeforeCollectCallback to register this callback. /// /// The state passed to JsSetBeforeCollectCallback. typedef void (CHAKRA_CALLBACK *JsBeforeCollectCallback)(_In_opt_ void *callbackState); /// /// A callback called before collecting an object. /// /// /// Use JsSetObjectBeforeCollectCallback to register this callback. /// /// The object to be collected. /// The state passed to JsSetObjectBeforeCollectCallback. typedef void (CHAKRA_CALLBACK *JsObjectBeforeCollectCallback)(_In_ JsRef ref, _In_opt_ void *callbackState); /// /// A background work item callback. /// /// /// This is passed to the host's thread service (if provided) to allow the host to /// invoke the work item callback on the background thread of its choice. /// /// Data argument passed to the thread service. typedef void (CHAKRA_CALLBACK *JsBackgroundWorkItemCallback)(_In_opt_ void *callbackState); /// /// A thread service callback. /// /// /// The host can specify a background thread service when calling JsCreateRuntime. If /// specified, then background work items will be passed to the host using this callback. The /// host is expected to either begin executing the background work item immediately and return /// true or return false and the runtime will handle the work item in-thread. /// /// The callback for the background work item. /// The data argument to be passed to the callback. typedef bool (CHAKRA_CALLBACK *JsThreadServiceCallback)(_In_ JsBackgroundWorkItemCallback callback, _In_opt_ void *callbackState); /// /// Called by the runtime when it is finished with all resources related to the script execution. /// The caller should free the source if loaded, the byte code, and the context at this time. /// /// The context passed to Js[Parse|Run]SerializedScriptWithCallback typedef void (CHAKRA_CALLBACK * JsSerializedScriptUnloadCallback)(_In_ JsSourceContext sourceContext); /// /// A finalizer callback. /// /// /// The external data that was passed in when creating the object being finalized. /// typedef void (CHAKRA_CALLBACK *JsFinalizeCallback)(_In_opt_ void *data); /// /// A function callback. /// /// /// A function object that represents the function being invoked. /// /// Indicates whether this is a regular call or a 'new' call. /// The arguments to the call. /// The number of arguments. /// /// The state passed to JsCreateFunction. /// /// The result of the call, if any. typedef _Ret_maybenull_ JsValueRef(CHAKRA_CALLBACK * JsNativeFunction)(_In_ JsValueRef callee, _In_ bool isConstructCall, _In_ JsValueRef *arguments, _In_ unsigned short argumentCount, _In_opt_ void *callbackState); /// /// A promise continuation callback. /// /// /// The host can specify a promise continuation callback in JsSetPromiseContinuationCallback. If /// a script creates a task to be run later, then the promise continuation callback will be called with /// the task and the task should be put in a FIFO queue, to be run when the current script is /// done executing. /// /// The task, represented as a JavaScript function. /// The data argument to be passed to the callback. typedef void (CHAKRA_CALLBACK *JsPromiseContinuationCallback)(_In_ JsValueRef task, _In_opt_ void *callbackState); /// /// Creates a new runtime. /// /// The attributes of the runtime to be created. /// The thread service for the runtime. Can be null. /// The runtime created. /// In the edge-mode binary, chakra.dll, this function lacks the runtimeVersion /// parameter (compare to jsrt9.h). /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateRuntime( _In_ JsRuntimeAttributes attributes, _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime); /// /// Performs a full garbage collection. /// /// The runtime in which the garbage collection will be performed. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCollectGarbage( _In_ JsRuntimeHandle runtime); /// /// Disposes a runtime. /// /// /// Once a runtime has been disposed, all resources owned by it are invalid and cannot be used. /// If the runtime is active (i.e. it is set to be current on a particular thread), it cannot /// be disposed. /// /// The runtime to dispose. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDisposeRuntime( _In_ JsRuntimeHandle runtime); /// /// Gets the current memory usage for a runtime. /// /// /// Memory usage can be always be retrieved, regardless of whether or not the runtime is active /// on another thread. /// /// The runtime whose memory usage is to be retrieved. /// The runtime's current memory usage, in bytes. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetRuntimeMemoryUsage( _In_ JsRuntimeHandle runtime, _Out_ size_t *memoryUsage); /// /// Gets the current memory limit for a runtime. /// /// /// The memory limit of a runtime can be always be retrieved, regardless of whether or not the /// runtime is active on another thread. /// /// The runtime whose memory limit is to be retrieved. /// /// The runtime's current memory limit, in bytes, or -1 if no limit has been set. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetRuntimeMemoryLimit( _In_ JsRuntimeHandle runtime, _Out_ size_t *memoryLimit); /// /// Sets the current memory limit for a runtime. /// /// /// /// A memory limit will cause any operation which exceeds the limit to fail with an "out of /// memory" error. Setting a runtime's memory limit to -1 means that the runtime has no memory /// limit. New runtimes default to having no memory limit. If the new memory limit exceeds /// current usage, the call will succeed and any future allocations in this runtime will fail /// until the runtime's memory usage drops below the limit. /// /// /// A runtime's memory limit can be always be set, regardless of whether or not the runtime is /// active on another thread. /// /// /// The runtime whose memory limit is to be set. /// /// The new runtime memory limit, in bytes, or -1 for no memory limit. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetRuntimeMemoryLimit( _In_ JsRuntimeHandle runtime, _In_ size_t memoryLimit); /// /// Sets a memory allocation callback for specified runtime /// /// /// /// Registering a memory allocation callback will cause the runtime to call back to the host /// whenever it acquires memory from, or releases memory to, the OS. The callback routine is /// called before the runtime memory manager allocates a block of memory. The allocation will /// be rejected if the callback returns false. The runtime memory manager will also invoke the /// callback routine after freeing a block of memory, as well as after allocation failures. /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// /// /// The return value of the callback is not stored; previously rejected allocations will not /// prevent the runtime from invoking the callback again later for new memory allocations. /// /// /// The runtime for which to register the allocation callback. /// /// User provided state that will be passed back to the callback. /// /// /// Memory allocation callback to be called for memory allocation events. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetRuntimeMemoryAllocationCallback( _In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsMemoryAllocationCallback allocationCallback); /// /// Sets a callback function that is called by the runtime before garbage collection. /// /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// /// /// The callback can be used by hosts to prepare for garbage collection. For example, by /// releasing unnecessary references on Chakra objects. /// /// /// The runtime for which to register the allocation callback. /// /// User provided state that will be passed back to the callback. /// /// The callback function being set. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetRuntimeBeforeCollectCallback( _In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsBeforeCollectCallback beforeCollectCallback); /// /// Adds a reference to a garbage collected object. /// /// /// This only needs to be called on JsRef handles that are not going to be stored /// somewhere on the stack. Calling JsAddRef ensures that the object the JsRef /// refers to will not be freed until JsRelease is called. /// /// The object to add a reference to. /// The object's new reference count (can pass in null). /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsAddRef( _In_ JsRef ref, _Out_opt_ unsigned int *count); /// /// Releases a reference to a garbage collected object. /// /// /// Removes a reference to a JsRef handle that was created by JsAddRef. /// /// The object to add a reference to. /// The object's new reference count (can pass in null). /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsRelease( _In_ JsRef ref, _Out_opt_ unsigned int *count); /// /// Sets a callback function that is called by the runtime before garbage collection of /// an object. /// /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// /// /// The object for which to register the callback. /// /// User provided state that will be passed back to the callback. /// /// The callback function being set. Use null to clear /// previously registered callback. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetObjectBeforeCollectCallback( _In_ JsRef ref, _In_opt_ void *callbackState, _In_ JsObjectBeforeCollectCallback objectBeforeCollectCallback); /// /// Creates a script context for running scripts. /// /// /// Each script context has its own global object that is isolated from all other script /// contexts. /// /// The runtime the script context is being created in. /// The created script context. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateContext( _In_ JsRuntimeHandle runtime, _Out_ JsContextRef *newContext); /// /// Gets the current script context on the thread. /// /// /// The current script context on the thread, null if there is no current script context. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetCurrentContext( _Out_ JsContextRef *currentContext); /// /// Sets the current script context on the thread. /// /// The script context to make current. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetCurrentContext( _In_ JsContextRef context); /// /// Gets the script context that the object belongs to. /// /// The object to get the context from. /// The context the object belongs to. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetContextOfObject( _In_ JsValueRef object, _Out_ JsContextRef *context); /// /// Gets the internal data set on JsrtContext. /// /// The context to get the data from. /// The pointer to the data where data will be returned. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetContextData( _In_ JsContextRef context, _Out_ void **data); /// /// Sets the internal data of JsrtContext. /// /// The context to set the data to. /// The pointer to the data to be set. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetContextData( _In_ JsContextRef context, _In_ void *data); /// /// Gets the runtime that the context belongs to. /// /// The context to get the runtime from. /// The runtime the context belongs to. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetRuntime( _In_ JsContextRef context, _Out_ JsRuntimeHandle *runtime); /// /// Tells the runtime to do any idle processing it need to do. /// /// /// /// If idle processing has been enabled for the current runtime, calling JsIdle will /// inform the current runtime that the host is idle and that the runtime can perform /// memory cleanup tasks. /// /// /// JsIdle can also return the number of system ticks until there will be more idle work /// for the runtime to do. Calling JsIdle before this number of ticks has passed will do /// no work. /// /// /// Requires an active script context. /// /// /// /// The next system tick when there will be more idle work to do. Can be null. Returns the /// maximum number of ticks if there no upcoming idle work to do. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsIdle( _Out_opt_ unsigned int *nextIdleTick); /// /// Gets the symbol associated with the property ID. /// /// /// /// Requires an active script context. /// /// /// The property ID to get the symbol of. /// The symbol associated with the property ID. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetSymbolFromPropertyId( _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *symbol); /// /// Gets the type of property /// /// /// /// Requires an active script context. /// /// /// The property ID to get the type of. /// The JsPropertyIdType of the given property ID /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetPropertyIdType( _In_ JsPropertyIdRef propertyId, _Out_ JsPropertyIdType* propertyIdType); /// /// Gets the property ID associated with the symbol. /// /// /// /// Property IDs are specific to a context and cannot be used across contexts. /// /// /// Requires an active script context. /// /// /// /// The symbol whose property ID is being retrieved. /// /// The property ID for the given symbol. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetPropertyIdFromSymbol( _In_ JsValueRef symbol, _Out_ JsPropertyIdRef *propertyId); /// /// Creates a Javascript symbol. /// /// /// Requires an active script context. /// /// The string description of the symbol. Can be null. /// The new symbol. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateSymbol( _In_ JsValueRef description, _Out_ JsValueRef *result); /// /// Gets the list of all symbol properties on the object. /// /// /// Requires an active script context. /// /// The object from which to get the property symbols. /// An array of property symbols. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetOwnPropertySymbols( _In_ JsValueRef object, _Out_ JsValueRef *propertySymbols); /// /// Gets the value of undefined in the current script context. /// /// /// Requires an active script context. /// /// The undefined value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetUndefinedValue( _Out_ JsValueRef *undefinedValue); /// /// Gets the value of null in the current script context. /// /// /// Requires an active script context. /// /// The null value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetNullValue( _Out_ JsValueRef *nullValue); /// /// Gets the value of true in the current script context. /// /// /// Requires an active script context. /// /// The true value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetTrueValue( _Out_ JsValueRef *trueValue); /// /// Gets the value of false in the current script context. /// /// /// Requires an active script context. /// /// The false value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetFalseValue( _Out_ JsValueRef *falseValue); /// /// Creates a Boolean value from a bool value. /// /// /// Requires an active script context. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsBoolToBoolean( _In_ bool value, _Out_ JsValueRef *booleanValue); /// /// Retrieves the bool value of a Boolean value. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsBooleanToBool( _In_ JsValueRef value, _Out_ bool *boolValue); /// /// Converts the value to Boolean using standard JavaScript semantics. /// /// /// Requires an active script context. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsConvertValueToBoolean( _In_ JsValueRef value, _Out_ JsValueRef *booleanValue); /// /// Gets the JavaScript type of a JsValueRef. /// /// The value whose type is to be returned. /// The type of the value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetValueType( _In_ JsValueRef value, _Out_ JsValueType *type); /// /// Creates a number value from a double value. /// /// /// Requires an active script context. /// /// The double to convert to a number value. /// The new number value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDoubleToNumber( _In_ double doubleValue, _Out_ JsValueRef *value); /// /// Creates a number value from an int value. /// /// /// Requires an active script context. /// /// The int to convert to a number value. /// The new number value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsIntToNumber( _In_ int intValue, _Out_ JsValueRef *value); /// /// Retrieves the double value of a number value. /// /// /// This function retrieves the value of a number value. It will fail with /// JsErrorInvalidArgument if the type of the value is not number. /// /// The number value to convert to a double value. /// The double value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsNumberToDouble( _In_ JsValueRef value, _Out_ double *doubleValue); /// /// Retrieves the int value of a number value. /// /// /// This function retrieves the value of a number value and converts to an int value. /// It will fail with JsErrorInvalidArgument if the type of the value is not number. /// /// The number value to convert to an int value. /// The int value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsNumberToInt( _In_ JsValueRef value, _Out_ int *intValue); /// /// Converts the value to number using standard JavaScript semantics. /// /// /// Requires an active script context. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsConvertValueToNumber( _In_ JsValueRef value, _Out_ JsValueRef *numberValue); /// /// Gets the length of a string value. /// /// The string value to get the length of. /// The length of the string. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetStringLength( _In_ JsValueRef stringValue, _Out_ int *length); /// /// Converts the value to string using standard JavaScript semantics. /// /// /// Requires an active script context. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsConvertValueToString( _In_ JsValueRef value, _Out_ JsValueRef *stringValue); /// /// Gets the global object in the current script context. /// /// /// Requires an active script context. /// /// The global object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetGlobalObject( _Out_ JsValueRef *globalObject); /// /// Creates a new object. /// /// /// Requires an active script context. /// /// The new object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateObject( _Out_ JsValueRef *object); /// /// Creates a new object that stores some external data. /// /// /// Requires an active script context. /// /// External data that the object will represent. May be null. /// /// A callback for when the object is finalized. May be null. /// /// The new object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateExternalObject( _In_opt_ void *data, _In_opt_ JsFinalizeCallback finalizeCallback, _Out_ JsValueRef *object); /// /// Converts the value to object using standard JavaScript semantics. /// /// /// Requires an active script context. /// /// The value to be converted. /// The converted value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsConvertValueToObject( _In_ JsValueRef value, _Out_ JsValueRef *object); /// /// Returns the prototype of an object. /// /// /// Requires an active script context. /// /// The object whose prototype is to be returned. /// The object's prototype. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetPrototype( _In_ JsValueRef object, _Out_ JsValueRef *prototypeObject); /// /// Sets the prototype of an object. /// /// /// Requires an active script context. /// /// The object whose prototype is to be changed. /// The object's new prototype. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetPrototype( _In_ JsValueRef object, _In_ JsValueRef prototypeObject); /// /// Performs JavaScript "instanceof" operator test. /// /// /// Requires an active script context. /// /// The object to test. /// The constructor function to test against. /// Whether "object instanceof constructor" is true. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsInstanceOf( _In_ JsValueRef object, _In_ JsValueRef constructor, _Out_ bool *result); /// /// Returns a value that indicates whether an object is extensible or not. /// /// /// Requires an active script context. /// /// The object to test. /// Whether the object is extensible or not. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetExtensionAllowed( _In_ JsValueRef object, _Out_ bool *value); /// /// Makes an object non-extensible. /// /// /// Requires an active script context. /// /// The object to make non-extensible. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsPreventExtension( _In_ JsValueRef object); /// /// Gets an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The ID of the property. /// The value of the property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *value); /// /// Gets a property descriptor for an object's own property. /// /// /// Requires an active script context. /// /// The object that has the property. /// The ID of the property. /// The property descriptor. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetOwnPropertyDescriptor( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *propertyDescriptor); /// /// Gets the list of all properties on the object. /// /// /// Requires an active script context. /// /// The object from which to get the property names. /// An array of property names. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetOwnPropertyNames( _In_ JsValueRef object, _Out_ JsValueRef *propertyNames); /// /// Puts an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The ID of the property. /// The new value of the property. /// The property set should follow strict mode rules. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ JsValueRef value, _In_ bool useStrictRules); /// /// Determines whether an object has a property. /// /// /// Requires an active script context. /// /// The object that may contain the property. /// The ID of the property. /// Whether the object (or a prototype) has the property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasProperty); /// /// Deletes an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The ID of the property. /// The property set should follow strict mode rules. /// Whether the property was deleted. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDeleteProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ bool useStrictRules, _Out_ JsValueRef *result); /// /// Defines a new object's own property from a property descriptor. /// /// /// Requires an active script context. /// /// The object that has the property. /// The ID of the property. /// The property descriptor. /// Whether the property was defined. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDefineProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ JsValueRef propertyDescriptor, _Out_ bool *result); /// /// Tests whether an object has a value at the specified index. /// /// /// Requires an active script context. /// /// The object to operate on. /// The index to test. /// Whether the object has a value at the specified index. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasIndexedProperty( _In_ JsValueRef object, _In_ JsValueRef index, _Out_ bool *result); /// /// Retrieve the value at the specified index of an object. /// /// /// Requires an active script context. /// /// The object to operate on. /// The index to retrieve. /// The retrieved value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetIndexedProperty( _In_ JsValueRef object, _In_ JsValueRef index, _Out_ JsValueRef *result); /// /// Set the value at the specified index of an object. /// /// /// Requires an active script context. /// /// The object to operate on. /// The index to set. /// The value to set. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetIndexedProperty( _In_ JsValueRef object, _In_ JsValueRef index, _In_ JsValueRef value); /// /// Delete the value at the specified index of an object. /// /// /// Requires an active script context. /// /// The object to operate on. /// The index to delete. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDeleteIndexedProperty( _In_ JsValueRef object, _In_ JsValueRef index); /// /// Determines whether an object has its indexed properties in external data. /// /// The object. /// Whether the object has its indexed properties in external data. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasIndexedPropertiesExternalData( _In_ JsValueRef object, _Out_ bool* value); /// /// Retrieves an object's indexed properties external data information. /// /// The object. /// The external data back store for the object's indexed properties. /// The array element type in external data. /// The number of array elements in external data. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetIndexedPropertiesExternalData( _In_ JsValueRef object, _Out_ void** data, _Out_ JsTypedArrayType* arrayType, _Out_ unsigned int* elementLength); /// /// Sets an object's indexed properties to external data. The external data will be used as back /// store for the object's indexed properties and accessed like a typed array. /// /// /// Requires an active script context. /// /// The object to operate on. /// The external data to be used as back store for the object's indexed properties. /// The array element type in external data. /// The number of array elements in external data. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetIndexedPropertiesToExternalData( _In_ JsValueRef object, _In_ void* data, _In_ JsTypedArrayType arrayType, _In_ unsigned int elementLength); /// /// Compare two JavaScript values for equality. /// /// /// /// This function is equivalent to the == operator in Javascript. /// /// /// Requires an active script context. /// /// /// The first object to compare. /// The second object to compare. /// Whether the values are equal. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsEquals( _In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result); /// /// Compare two JavaScript values for strict equality. /// /// /// /// This function is equivalent to the === operator in Javascript. /// /// /// Requires an active script context. /// /// /// The first object to compare. /// The second object to compare. /// Whether the values are strictly equal. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsStrictEquals( _In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result); /// /// Determines whether an object is an external object. /// /// The object. /// Whether the object is an external object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasExternalData( _In_ JsValueRef object, _Out_ bool *value); /// /// Retrieves the data from an external object. /// /// The external object. /// /// The external data stored in the object. Can be null if no external data is stored in the /// object. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetExternalData( _In_ JsValueRef object, _Out_ void **externalData); /// /// Sets the external data on an external object. /// /// The external object. /// /// The external data to be stored in the object. Can be null if no external data is /// to be stored in the object. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetExternalData( _In_ JsValueRef object, _In_opt_ void *externalData); /// /// Creates a Javascript array object. /// /// /// Requires an active script context. /// /// The initial length of the array. /// The new array object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateArray( _In_ unsigned int length, _Out_ JsValueRef *result); /// /// Creates a Javascript ArrayBuffer object. /// /// /// Requires an active script context. /// /// /// The number of bytes in the ArrayBuffer. /// /// The new ArrayBuffer object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateArrayBuffer( _In_ unsigned int byteLength, _Out_ JsValueRef *result); /// /// Creates a Javascript ArrayBuffer object to access external memory. /// /// Requires an active script context. /// A pointer to the external memory. /// The number of bytes in the external memory. /// A callback for when the object is finalized. May be null. /// User provided state that will be passed back to finalizeCallback. /// The new ArrayBuffer object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateExternalArrayBuffer( _Pre_maybenull_ _Pre_writable_byte_size_(byteLength) void *data, _In_ unsigned int byteLength, _In_opt_ JsFinalizeCallback finalizeCallback, _In_opt_ void *callbackState, _Out_ JsValueRef *result); /// /// Creates a Javascript typed array object. /// /// /// /// The baseArray can be an ArrayBuffer, another typed array, or a JavaScript /// Array. The returned typed array will use the baseArray if it is an ArrayBuffer, or /// otherwise create and use a copy of the underlying source array. /// /// /// Requires an active script context. /// /// /// The type of the array to create. /// /// The base array of the new array. Use JS_INVALID_REFERENCE if no base array. /// /// /// The offset in bytes from the start of baseArray (ArrayBuffer) for result typed array to reference. /// Only applicable when baseArray is an ArrayBuffer object. Must be 0 otherwise. /// /// /// The number of elements in the array. Only applicable when creating a new typed array without /// baseArray (baseArray is JS_INVALID_REFERENCE) or when baseArray is an ArrayBuffer object. /// Must be 0 otherwise. /// /// The new typed array object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateTypedArray( _In_ JsTypedArrayType arrayType, _In_ JsValueRef baseArray, _In_ unsigned int byteOffset, _In_ unsigned int elementLength, _Out_ JsValueRef *result); /// /// Creates a Javascript DataView object. /// /// /// Requires an active script context. /// /// /// An existing ArrayBuffer object to use as the storage for the result DataView object. /// /// /// The offset in bytes from the start of arrayBuffer for result DataView to reference. /// /// /// The number of bytes in the ArrayBuffer for result DataView to reference. /// /// The new DataView object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateDataView( _In_ JsValueRef arrayBuffer, _In_ unsigned int byteOffset, _In_ unsigned int byteLength, _Out_ JsValueRef *result); /// /// Obtains frequently used properties of a typed array. /// /// The typed array instance. /// The type of the array. /// The ArrayBuffer backstore of the array. /// The offset in bytes from the start of arrayBuffer referenced by the array. /// The number of bytes in the array. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetTypedArrayInfo( _In_ JsValueRef typedArray, _Out_opt_ JsTypedArrayType *arrayType, _Out_opt_ JsValueRef *arrayBuffer, _Out_opt_ unsigned int *byteOffset, _Out_opt_ unsigned int *byteLength); /// /// Obtains the underlying memory storage used by an ArrayBuffer. /// /// The ArrayBuffer instance. /// /// The ArrayBuffer's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the ArrayBuffer. The buffer pointer does not count as a reference to the ArrayBuffer for the purpose /// of garbage collection. /// /// The number of bytes in the buffer. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetArrayBufferStorage( _In_ JsValueRef arrayBuffer, _Outptr_result_bytebuffer_(*bufferLength) ChakraBytePtr *buffer, _Out_ unsigned int *bufferLength); /// /// Obtains the underlying memory storage used by a typed array. /// /// The typed array instance. /// /// The array's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the array. The buffer pointer does not count as a reference to the array for the purpose /// of garbage collection. /// /// The number of bytes in the buffer. /// The type of the array. /// /// The size of an element of the array. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetTypedArrayStorage( _In_ JsValueRef typedArray, _Outptr_result_bytebuffer_(*bufferLength) ChakraBytePtr *buffer, _Out_ unsigned int *bufferLength, _Out_opt_ JsTypedArrayType *arrayType, _Out_opt_ int *elementSize); /// /// Obtains the underlying memory storage used by a DataView. /// /// The DataView instance. /// /// The DataView's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the DataView. The buffer pointer does not count as a reference to the DataView for the purpose /// of garbage collection. /// /// The number of bytes in the buffer. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetDataViewStorage( _In_ JsValueRef dataView, _Outptr_result_bytebuffer_(*bufferLength) ChakraBytePtr *buffer, _Out_ unsigned int *bufferLength); /// /// Invokes a function. /// /// /// Requires thisArg as first argument of arguments. /// Requires an active script context. /// /// The function to invoke. /// The arguments to the call. /// The number of arguments being passed in to the function. /// The value returned from the function invocation, if any. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCallFunction( _In_ JsValueRef function, _In_reads_(argumentCount) JsValueRef *arguments, _In_ unsigned short argumentCount, _Out_opt_ JsValueRef *result); /// /// Invokes a function as a constructor. /// /// /// Requires an active script context. /// /// The function to invoke as a constructor. /// The arguments to the call. /// The number of arguments being passed in to the function. /// The value returned from the function invocation. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsConstructObject( _In_ JsValueRef function, _In_reads_(argumentCount) JsValueRef *arguments, _In_ unsigned short argumentCount, _Out_ JsValueRef *result); /// /// Creates a new JavaScript function. /// /// /// Requires an active script context. /// /// The method to call when the function is invoked. /// /// User provided state that will be passed back to the callback. /// /// The new function object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateFunction( _In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function); /// /// Creates a new JavaScript function with name. /// /// /// Requires an active script context. /// /// The name of this function that will be used for diagnostics and stringification purposes. /// The method to call when the function is invoked. /// /// User provided state that will be passed back to the callback. /// /// The new function object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateNamedFunction( _In_ JsValueRef name, _In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function); /// /// Creates a new JavaScript error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Creates a new JavaScript RangeError error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateRangeError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Creates a new JavaScript ReferenceError error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateReferenceError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Creates a new JavaScript SyntaxError error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateSyntaxError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Creates a new JavaScript TypeError error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateTypeError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Creates a new JavaScript URIError error object /// /// /// Requires an active script context. /// /// Message for the error object. /// The new error object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateURIError( _In_ JsValueRef message, _Out_ JsValueRef *error); /// /// Determines whether the runtime of the current context is in an exception state. /// /// /// /// If a call into the runtime results in an exception (either as the result of running a /// script or due to something like a conversion failure), the runtime is placed into an /// "exception state." All calls into any context created by the runtime (except for the /// exception APIs) will fail with JsErrorInExceptionState until the exception is /// cleared. /// /// /// If the runtime of the current context is in the exception state when a callback returns /// into the engine, the engine will automatically rethrow the exception. /// /// /// Requires an active script context. /// /// /// /// Whether the runtime of the current context is in the exception state. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasException( _Out_ bool *hasException); /// /// Returns the exception that caused the runtime of the current context to be in the /// exception state and resets the exception state for that runtime. /// /// /// /// If the runtime of the current context is not in an exception state, this API will return /// JsErrorInvalidArgument. If the runtime is disabled, this will return an exception /// indicating that the script was terminated, but it will not clear the exception (the /// exception will be cleared if the runtime is re-enabled using /// JsEnableRuntimeExecution). /// /// /// Requires an active script context. /// /// /// The exception for the runtime of the current context. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetAndClearException( _Out_ JsValueRef *exception); /// /// Sets the runtime of the current context to an exception state. /// /// /// /// If the runtime of the current context is already in an exception state, this API will /// return JsErrorInExceptionState. /// /// /// Requires an active script context. /// /// /// /// The JavaScript exception to set for the runtime of the current context. /// /// /// JsNoError if the engine was set into an exception state, a failure code otherwise. /// CHAKRA_API JsSetException( _In_ JsValueRef exception); /// /// Suspends script execution and terminates any running scripts in a runtime. /// /// /// /// Calls to a suspended runtime will fail until JsEnableRuntimeExecution is called. /// /// /// This API does not have to be called on the thread the runtime is active on. Although the /// runtime will be set into a suspended state, an executing script may not be suspended /// immediately; a running script will be terminated with an uncatchable exception as soon as /// possible. /// /// /// Suspending execution in a runtime that is already suspended is a no-op. /// /// /// The runtime to be suspended. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsDisableRuntimeExecution( _In_ JsRuntimeHandle runtime); /// /// Enables script execution in a runtime. /// /// /// Enabling script execution in a runtime that already has script execution enabled is a /// no-op. /// /// The runtime to be enabled. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsEnableRuntimeExecution( _In_ JsRuntimeHandle runtime); /// /// Returns a value that indicates whether script execution is disabled in the runtime. /// /// Specifies the runtime to check if execution is disabled. /// If execution is disabled, true, false otherwise. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsIsRuntimeExecutionDisabled( _In_ JsRuntimeHandle runtime, _Out_ bool *isDisabled); /// /// Sets a promise continuation callback function that is called by the context when a task /// needs to be queued for future execution /// /// /// /// Requires an active script context. /// /// /// The callback function being set. /// /// User provided state that will be passed back to the callback. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetPromiseContinuationCallback( _In_opt_ JsPromiseContinuationCallback promiseContinuationCallback, _In_opt_ void *callbackState); #ifdef _WIN32 #include "ChakraCommonWindows.h" #endif // _WIN32 #endif // _CHAKRACOMMON_H_ ================================================ FILE: include/ChakraCore.h ================================================ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to host Chakra. /// /// \file /// \brief The Chakra Core hosting API. /// /// This file contains a flat C API layer. This is the API exported by ChakraCore.dll. #ifdef _MSC_VER #pragma once #endif // _MSC_VER #ifndef _CHAKRACORE_H_ #define _CHAKRACORE_H_ #if !defined(NTBUILD) && !defined(_CHAKRACOREBUILD) #define _CHAKRACOREBUILD #endif #include "ChakraCommon.h" #include "ChakraDebug.h" // Begin ChakraCore only APIs #ifdef _CHAKRACOREBUILD /// /// A reference to an ES module. /// /// /// A module record represents an ES module. /// typedef void* JsModuleRecord; /// /// A reference to an object owned by the SharedArrayBuffer. /// /// /// This represents SharedContents which is heap allocated object, it can be passed through /// different runtimes to share the underlying buffer. /// typedef void *JsSharedArrayBufferContentHandle; /// /// Flags for parsing a module. /// typedef enum JsParseModuleSourceFlags { /// /// Module source is UTF16. /// JsParseModuleSourceFlags_DataIsUTF16LE = 0x00000000, /// /// Module source is UTF8. /// JsParseModuleSourceFlags_DataIsUTF8 = 0x00000001 } JsParseModuleSourceFlags; /// /// The types of host info that can be set on a module record with JsSetModuleHostInfo. /// /// /// For more information see JsSetModuleHostInfo. /// typedef enum JsModuleHostInfoKind { /// /// An exception object - e.g. if the module file cannot be found. /// JsModuleHostInfo_Exception = 0x01, /// /// Host defined info. /// JsModuleHostInfo_HostDefined = 0x02, /// /// Callback for receiving notification when module is ready. /// JsModuleHostInfo_NotifyModuleReadyCallback = 0x3, /// /// Callback for receiving notification to fetch a dependent module. /// JsModuleHostInfo_FetchImportedModuleCallback = 0x4, /// /// Callback for receiving notification for calls to ```import()``` /// JsModuleHostInfo_FetchImportedModuleFromScriptCallback = 0x5, /// /// URL for use in error stack traces and debugging. /// JsModuleHostInfo_Url = 0x6 } JsModuleHostInfoKind; /// /// The possible states for a Promise object. /// typedef enum _JsPromiseState { JsPromiseStatePending = 0x0, JsPromiseStateFulfilled = 0x1, JsPromiseStateRejected = 0x2 } JsPromiseState; /// /// User implemented callback to fetch additional imported modules in ES modules. /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is blocked until /// the callback completes. Notify the host to fetch the dependent module. This is the "import" part /// before HostResolveImportedModule in ES6 spec. This notifies the host that the referencing module has /// the specified module dependency, and the host needs to retrieve the module back. /// /// Callback should: /// 1. Check if the requested module has been requested before - if yes return the existing /// module record /// 2. If no create and initialize a new module record with JsInitializeModuleRecord to /// return and schedule a call to JsParseModuleSource for the new record. /// /// The referencing module that is requesting the dependent module. /// The specifier coming from the module source code. /// The ModuleRecord of the dependent module. If the module was requested /// before from other source, return the existing ModuleRecord, otherwise /// return a newly created ModuleRecord. /// /// Returns a JsNoError if the operation succeeded an error code otherwise. /// typedef JsErrorCode(CHAKRA_CALLBACK * FetchImportedModuleCallBack)(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord); /// /// User implemented callback to fetch imported modules dynamically in scripts. /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is blocked untill /// the callback completes. Notify the host to fetch the dependent module. This is used for the dynamic /// import() syntax. /// /// Callback should: /// 1. Check if the requested module has been requested before - if yes return the existing module record /// 2. If no create and initialize a new module record with JsInitializeModuleRecord to return and /// schedule a call to JsParseModuleSource for the new record. /// /// The referencing script context that calls import() /// The specifier provided to the import() call. /// The ModuleRecord of the dependent module. If the module was requested /// before from other source, return the existing ModuleRecord, otherwise /// return a newly created ModuleRecord. /// /// Returns JsNoError if the operation succeeded or an error code otherwise. /// typedef JsErrorCode(CHAKRA_CALLBACK * FetchImportedModuleFromScriptCallBack)(_In_ JsSourceContext dwReferencingSourceContext, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord); /// /// User implemented callback to get notification when the module is ready. /// /// /// The callback is invoked on the current runtime execution thread, therefore execution is blocked until the /// callback completes. This callback should schedule a call to JsEvaluateModule to run the module that has been loaded. /// /// The referencing module that has finished running ModuleDeclarationInstantiation step. /// If nullptr, the module is successfully initialized and host should queue the execution job /// otherwise it's the exception object. /// /// Returns a JsErrorCode - note, the return value is ignored. /// typedef JsErrorCode(CHAKRA_CALLBACK * NotifyModuleReadyCallback)(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar); /// /// A structure containing information about a native function callback. /// typedef struct JsNativeFunctionInfo { JsValueRef thisArg; JsValueRef newTargetArg; bool isConstructCall; }JsNativeFunctionInfo; /// /// A function callback. /// /// /// A function object that represents the function being invoked. /// /// The arguments to the call. /// The number of arguments. /// Additional information about this function call. /// /// The state passed to JsCreateFunction. /// /// The result of the call, if any. typedef _Ret_maybenull_ JsValueRef(CHAKRA_CALLBACK * JsEnhancedNativeFunction)(_In_ JsValueRef callee, _In_ JsValueRef *arguments, _In_ unsigned short argumentCount, _In_ JsNativeFunctionInfo *info, _In_opt_ void *callbackState); /// /// A Promise Rejection Tracker callback. /// /// /// The host can specify a promise rejection tracker callback in JsSetHostPromiseRejectionTracker. /// If a promise is rejected with no reactions or a reaction is added to a promise that was rejected /// before it had reactions by default nothing is done. /// A Promise Rejection Tracker callback may be set - which will then be called when this occurs. /// Note - per draft ECMASpec 2018 25.4.1.9 this function should not set or return an exception /// Note also the promise and reason parameters may be garbage collected after this function is called /// if you wish to make further use of them you will need to use JsAddRef to preserve them /// However if you use JsAddRef you must also call JsRelease and not hold unto them after /// a handled notification (both per spec and to avoid memory leaks) /// /// The promise object, represented as a JsValueRef. /// The value/cause of the rejection, represented as a JsValueRef. /// Boolean - false for promiseRejected: i.e. if the promise has just been rejected with no handler, /// true for promiseHandled: i.e. if it was rejected before without a handler and is now being handled. /// The state passed to JsSetHostPromiseRejectionTracker. typedef void (CHAKRA_CALLBACK *JsHostPromiseRejectionTrackerCallback)(_In_ JsValueRef promise, _In_ JsValueRef reason, _In_ bool handled, _In_opt_ void *callbackState); /// /// Creates a new enhanced JavaScript function. /// /// /// Requires an active script context. /// /// The method to call when the function is invoked. /// If this is not JS_INVALID_REFERENCE, it is converted to a string and used as the name of the function. /// /// User provided state that will be passed back to the callback. /// /// The new function object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateEnhancedFunction( _In_ JsEnhancedNativeFunction nativeFunction, _In_opt_ JsValueRef metadata, _In_opt_ void *callbackState, _Out_ JsValueRef *function); /// /// Initialize a ModuleRecord from host /// /// /// Bootstrap the module loading process by creating a new module record. /// /// The parent module of the new module - nullptr for a root module. /// The normalized specifier for the module. /// The new module record. The host should not try to call this API twice /// with the same normalizedSpecifier. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsInitializeModuleRecord( _In_opt_ JsModuleRecord referencingModule, _In_ JsValueRef normalizedSpecifier, _Outptr_result_maybenull_ JsModuleRecord* moduleRecord); /// /// Parse the source for an ES module /// /// /// This is basically ParseModule operation in ES6 spec. It is slightly different in that: /// a) The ModuleRecord was initialized earlier, and passed in as an argument. /// b) This includes a check to see if the module being Parsed is the last module in the /// dependency tree. If it is it automatically triggers Module Instantiation. /// /// The ModuleRecord being parsed. /// A cookie identifying the script that can be used by debuggable script contexts. /// The source script to be parsed, but not executed in this code. /// The length of sourceText in bytes. As the input might contain a embedded null. /// The type of the source code passed in. It could be utf16 or utf8 at this time. /// The error object if there is parse error. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsParseModuleSource( _In_ JsModuleRecord requestModule, _In_ JsSourceContext sourceContext, _In_ BYTE* script, _In_ unsigned int scriptLength, _In_ JsParseModuleSourceFlags sourceFlag, _Outptr_result_maybenull_ JsValueRef* exceptionValueRef); /// /// Execute module code. /// /// /// This method implements 15.2.1.1.6.5, "ModuleEvaluation" concrete method. /// This method should be called after the engine notifies the host that the module is ready. /// This method only needs to be called on root modules - it will execute all of the dependent modules. /// /// One moduleRecord will be executed only once. Additional execution call on the same moduleRecord will fail. /// /// The ModuleRecord being executed. /// The return value of the module. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsModuleEvaluation( _In_ JsModuleRecord requestModule, _Outptr_result_maybenull_ JsValueRef* result); /// /// Set host info for the specified module. /// /// /// This is used for four things: /// 1. Setting up the callbacks for module loading - note these are actually /// set on the current Context not the module so only have to be set for /// the first root module in any given context. /// 2. Setting host defined info on a module record - can be anything that /// you wish to associate with your modules. /// 3. Setting a URL for a module to be used for stack traces/debugging - /// note this must be set before calling JsParseModuleSource on the module /// or it will be ignored. /// 4. Setting an exception on the module object - only relevant prior to it being Parsed. /// /// The request module. /// The type of host info to be set. /// The host info to be set. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetModuleHostInfo( _In_ JsModuleRecord requestModule, _In_ JsModuleHostInfoKind moduleHostInfo, _In_ void* hostInfo); /// /// Retrieve the host info for the specified module. /// /// /// This can used to retrieve info previously set with JsSetModuleHostInfo. /// /// The request module. /// The type of host info to be retrieved. /// The retrieved host info for the module. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetModuleHostInfo( _In_ JsModuleRecord requestModule, _In_ JsModuleHostInfoKind moduleHostInfo, _Outptr_result_maybenull_ void** hostInfo); /// /// Returns metadata relating to the exception that caused the runtime of the current context /// to be in the exception state and resets the exception state for that runtime. The metadata /// includes a reference to the exception itself. /// /// /// /// If the runtime of the current context is not in an exception state, this API will return /// JsErrorInvalidArgument. If the runtime is disabled, this will return an exception /// indicating that the script was terminated, but it will not clear the exception (the /// exception will be cleared if the runtime is re-enabled using /// JsEnableRuntimeExecution). /// /// /// The metadata value is a javascript object with the following properties: exception, the /// thrown exception object; line, the 0 indexed line number where the exception was thrown; /// column, the 0 indexed column number where the exception was thrown; length, the /// source-length of the cause of the exception; source, a string containing the line of /// source code where the exception was thrown; and url, a string containing the name of /// the script file containing the code that threw the exception. /// /// /// Requires an active script context. /// /// /// The exception metadata for the runtime of the current context. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetAndClearExceptionWithMetadata( _Out_ JsValueRef *metadata); /// /// Called by the runtime to load the source code of the serialized script. /// /// The context passed to Js[Parse|Run]SerializedScriptCallback /// The script returned. /// /// true if the operation succeeded, false otherwise. /// typedef bool (CHAKRA_CALLBACK * JsSerializedLoadScriptCallback) (JsSourceContext sourceContext, _Out_ JsValueRef *value, _Out_ JsParseScriptAttributes *parseAttributes); /// /// Create JavascriptString variable from ASCII or Utf8 string /// /// /// /// Requires an active script context. /// /// /// Input string can be either ASCII or Utf8 /// /// /// Pointer to string memory. /// Number of bytes within the string /// JsValueRef representing the JavascriptString /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateString( _In_ const char *content, _In_ size_t length, _Out_ JsValueRef *value); /// /// Create JavascriptString variable from Utf16 string /// /// /// /// Requires an active script context. /// /// /// Expects Utf16 string /// /// /// Pointer to string memory. /// Number of characters within the string /// JsValueRef representing the JavascriptString /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateStringUtf16( _In_ const uint16_t *content, _In_ size_t length, _Out_ JsValueRef *value); /// /// Write JavascriptString value into C string buffer (Utf8) /// /// /// /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `length` argument will return the length needed. /// /// /// JavascriptString value /// Pointer to buffer /// Buffer size /// Total number of characters needed or written /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCopyString( _In_ JsValueRef value, _Out_opt_ char* buffer, _In_ size_t bufferSize, _Out_opt_ size_t* length); /// /// Write string value into Utf16 string buffer /// /// /// /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `written` argument will return the length needed. /// /// /// when start is out of range or < 0, returns JsErrorInvalidArgument /// and `written` will be equal to 0. /// If calculated length is 0 (It can be due to string length or `start` /// and length combination), then `written` will be equal to 0 and call /// returns JsNoError /// /// /// JavascriptString value /// start offset of buffer /// length to be written /// Pointer to buffer /// Total number of characters written /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCopyStringUtf16( _In_ JsValueRef value, _In_ int start, _In_ int length, _Out_opt_ uint16_t* buffer, _Out_opt_ size_t* written); /// /// Parses a script and returns a function representing the script. /// /// /// /// Requires an active script context. /// /// /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// /// /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// /// /// The script to run. /// /// A cookie identifying the script that can be used by debuggable script contexts. /// /// The location the script came from. /// Attribute mask for parsing the script /// The result of the compiled script. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsParse( _In_ JsValueRef script, _In_ JsSourceContext sourceContext, _In_ JsValueRef sourceUrl, _In_ JsParseScriptAttributes parseAttributes, _Out_ JsValueRef *result); /// /// Executes a script. /// /// /// /// Requires an active script context. /// /// /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// /// /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// /// /// The script to run. /// /// A cookie identifying the script that can be used by debuggable script contexts. /// /// The location the script came from /// Attribute mask for parsing the script /// The result of the script, if any. This parameter can be null. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsRun( _In_ JsValueRef script, _In_ JsSourceContext sourceContext, _In_ JsValueRef sourceUrl, _In_ JsParseScriptAttributes parseAttributes, _Out_ JsValueRef *result); /// /// Creates the property ID associated with the name. /// /// /// /// Property IDs are specific to a context and cannot be used across contexts. /// /// /// Requires an active script context. /// /// /// /// The name of the property ID to get or create. The name may consist of only digits. /// The string is expected to be ASCII / utf8 encoded. /// /// length of the name in bytes /// The property ID in this runtime for the given name. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreatePropertyId( _In_z_ const char *name, _In_ size_t length, _Out_ JsPropertyIdRef *propertyId); /// /// Copies the name associated with the property ID into a buffer. /// /// /// /// Requires an active script context. /// /// /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// `length` argument will return the size needed. /// /// /// The property ID to get the name of. /// The buffer holding the name associated with the property ID, encoded as utf8 /// Size of the buffer. /// Total number of characters written or to be written /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCopyPropertyId( _In_ JsPropertyIdRef propertyId, _Out_ char* buffer, _In_ size_t bufferSize, _Out_ size_t* length); /// /// Serializes a parsed script to a buffer than can be reused. /// /// /// /// JsSerializeScript parses a script and then stores the parsed form of the script in a /// runtime-independent format. The serialized script then can be deserialized in any /// runtime without requiring the script to be re-parsed. /// /// /// Requires an active script context. /// /// /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// /// /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// /// /// The script to serialize /// ArrayBuffer /// Encoding for the script. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSerialize( _In_ JsValueRef script, _Out_ JsValueRef *buffer, _In_ JsParseScriptAttributes parseAttributes); /// /// Parses a serialized script and returns a function representing the script. /// Provides the ability to lazy load the script source only if/when it is needed. /// /// /// /// Requires an active script context. /// /// /// The serialized script as an ArrayBuffer (preferably ExternalArrayBuffer). /// /// Callback called when the source code of the script needs to be loaded. /// This is an optional parameter, set to null if not needed. /// /// /// A cookie identifying the script that can be used by debuggable script contexts. /// This context will passed into scriptLoadCallback. /// /// The location the script came from. /// A function representing the script code. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsParseSerialized( _In_ JsValueRef buffer, _In_ JsSerializedLoadScriptCallback scriptLoadCallback, _In_ JsSourceContext sourceContext, _In_ JsValueRef sourceUrl, _Out_ JsValueRef *result); /// /// Runs a serialized script. /// Provides the ability to lazy load the script source only if/when it is needed. /// /// /// /// Requires an active script context. /// /// /// The runtime will detach the data from the buffer and hold on to it until all /// instances of any functions created from the buffer are garbage collected. /// /// /// The serialized script as an ArrayBuffer (preferably ExternalArrayBuffer). /// Callback called when the source code of the script needs to be loaded. /// /// A cookie identifying the script that can be used by debuggable script contexts. /// This context will passed into scriptLoadCallback. /// /// The location the script came from. /// /// The result of running the script, if any. This parameter can be null. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsRunSerialized( _In_ JsValueRef buffer, _In_ JsSerializedLoadScriptCallback scriptLoadCallback, _In_ JsSourceContext sourceContext, _In_ JsValueRef sourceUrl, _Out_ JsValueRef *result); /// /// Gets the state of a given Promise object. /// /// /// Requires an active script context. /// /// The Promise object. /// The current state of the Promise. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetPromiseState( _In_ JsValueRef promise, _Out_ JsPromiseState *state); /// /// Gets the result of a given Promise object. /// /// /// Requires an active script context. /// /// The Promise object. /// The result of the Promise. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetPromiseResult( _In_ JsValueRef promise, _Out_ JsValueRef *result); /// /// Creates a new JavaScript Promise object. /// /// /// Requires an active script context. /// /// The new Promise object. /// The function called to resolve the created Promise object. /// The function called to reject the created Promise object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreatePromise( _Out_ JsValueRef *promise, _Out_ JsValueRef *resolveFunction, _Out_ JsValueRef *rejectFunction); /// /// A weak reference to a JavaScript value. /// /// /// A value with only weak references is available for garbage-collection. A strong reference /// to the value (JsValueRef) may be obtained from a weak reference if the value happens /// to still be available. /// typedef JsRef JsWeakRef; /// /// Creates a weak reference to a value. /// /// The value to be referenced. /// Weak reference to the value. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateWeakReference( _In_ JsValueRef value, _Out_ JsWeakRef* weakRef); /// /// Gets a strong reference to the value referred to by a weak reference. /// /// A weak reference. /// Reference to the value, or JS_INVALID_REFERENCE if the value is /// no longer available. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetWeakReferenceValue( _In_ JsWeakRef weakRef, _Out_ JsValueRef* value); /// /// Creates a Javascript SharedArrayBuffer object with shared content get from JsGetSharedArrayBufferContent. /// /// /// Requires an active script context. /// /// /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// /// The new SharedArrayBuffer object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateSharedArrayBufferWithSharedContent( _In_ JsSharedArrayBufferContentHandle sharedContents, _Out_ JsValueRef *result); /// /// Get the storage object from a SharedArrayBuffer. /// /// /// Requires an active script context. /// /// The SharedArrayBuffer object. /// /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// User should call JsReleaseSharedArrayBufferContentHandle after finished using it. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetSharedArrayBufferContent( _In_ JsValueRef sharedArrayBuffer, _Out_ JsSharedArrayBufferContentHandle *sharedContents); /// /// Decrease the reference count on a SharedArrayBuffer storage object. /// /// /// Requires an active script context. /// /// /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsReleaseSharedArrayBufferContentHandle( _In_ JsSharedArrayBufferContentHandle sharedContents); /// /// Determines whether an object has a non-inherited property. /// /// /// Requires an active script context. /// /// The object that may contain the property. /// The ID of the property. /// Whether the object has the non-inherited property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsHasOwnProperty( _In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasOwnProperty); /// /// Write JS string value into char string buffer without a null terminator /// /// /// /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `written` argument will return the length needed. /// /// /// When start is out of range or < 0, returns JsErrorInvalidArgument /// and `written` will be equal to 0. /// If calculated length is 0 (It can be due to string length or `start` /// and length combination), then `written` will be equal to 0 and call /// returns JsNoError /// /// /// The JS string `value` will be converted one utf16 code point at a time, /// and if it has code points that do not fit in one byte, those values /// will be truncated. /// /// /// JavascriptString value /// Start offset of buffer /// Number of characters to be written /// Pointer to buffer /// Total number of characters written /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCopyStringOneByte( _In_ JsValueRef value, _In_ int start, _In_ int length, _Out_opt_ char* buffer, _Out_opt_ size_t* written); /// /// Obtains frequently used properties of a data view. /// /// The data view instance. /// The ArrayBuffer backstore of the view. /// The offset in bytes from the start of arrayBuffer referenced by the array. /// The number of bytes in the array. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetDataViewInfo( _In_ JsValueRef dataView, _Out_opt_ JsValueRef *arrayBuffer, _Out_opt_ unsigned int *byteOffset, _Out_opt_ unsigned int *byteLength); /// /// Determine if one JavaScript value is less than another JavaScript value. /// /// /// /// This function is equivalent to the < operator in Javascript. /// /// /// Requires an active script context. /// /// /// The first object to compare. /// The second object to compare. /// Whether object1 is less than object2. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsLessThan( _In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result); /// /// Determine if one JavaScript value is less than or equal to another JavaScript value. /// /// /// /// This function is equivalent to the <= operator in Javascript. /// /// /// Requires an active script context. /// /// /// The first object to compare. /// The second object to compare. /// Whether object1 is less than or equal to object2. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsLessThanOrEqual( _In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result); /// /// Creates a new object (with prototype) that stores some external data. /// /// /// Requires an active script context. /// /// External data that the object will represent. May be null. /// /// A callback for when the object is finalized. May be null. /// /// Prototype object or nullptr. /// The new object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsCreateExternalObjectWithPrototype( _In_opt_ void *data, _In_opt_ JsFinalizeCallback finalizeCallback, _In_opt_ JsValueRef prototype, _Out_ JsValueRef *object); /// /// Gets an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// The value of the property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectGetProperty( _In_ JsValueRef object, _In_ JsValueRef key, _Out_ JsValueRef *value); /// /// Puts an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// The new value of the property. /// The property set should follow strict mode rules. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectSetProperty( _In_ JsValueRef object, _In_ JsValueRef key, _In_ JsValueRef value, _In_ bool useStrictRules); /// /// Determines whether an object has a property. /// /// /// Requires an active script context. /// /// The object that may contain the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// Whether the object (or a prototype) has the property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectHasProperty( _In_ JsValueRef object, _In_ JsValueRef key, _Out_ bool *hasProperty); /// /// Defines a new object's own property from a property descriptor. /// /// /// Requires an active script context. /// /// The object that has the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// The property descriptor. /// Whether the property was defined. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectDefineProperty( _In_ JsValueRef object, _In_ JsValueRef key, _In_ JsValueRef propertyDescriptor, _Out_ bool *result); /// /// Deletes an object's property. /// /// /// Requires an active script context. /// /// The object that contains the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// The property set should follow strict mode rules. /// Whether the property was deleted. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectDeleteProperty( _In_ JsValueRef object, _In_ JsValueRef key, _In_ bool useStrictRules, _Out_ JsValueRef *result); /// /// Gets a property descriptor for an object's own property. /// /// /// Requires an active script context. /// /// The object that has the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// The property descriptor. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectGetOwnPropertyDescriptor( _In_ JsValueRef object, _In_ JsValueRef key, _Out_ JsValueRef *propertyDescriptor); /// /// Determines whether an object has a non-inherited property. /// /// /// Requires an active script context. /// /// The object that may contain the property. /// The key (JavascriptString or JavascriptSymbol) to the property. /// Whether the object has the non-inherited property. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsObjectHasOwnProperty( _In_ JsValueRef object, _In_ JsValueRef key, _Out_ bool *hasOwnProperty); /// /// Sets whether any action should be taken when a promise is rejected with no reactions /// or a reaction is added to a promise that was rejected before it had reactions. /// By default in either of these cases nothing occurs. /// This function allows you to specify if something should occur and provide a callback /// to implement whatever should occur. /// /// /// Requires an active script context. /// /// The callback function being set. /// /// User provided state that will be passed back to the callback. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSetHostPromiseRejectionTracker( _In_ JsHostPromiseRejectionTrackerCallback promiseRejectionTrackerCallback, _In_opt_ void *callbackState); /// /// Retrieve the namespace object for a module. /// /// /// Requires an active script context and that the module has already been evaluated. /// /// The JsModuleRecord for which the namespace is being requested. /// A JsValueRef - the requested namespace object. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetModuleNamespace( _In_ JsModuleRecord requestModule, _Outptr_result_maybenull_ JsValueRef *moduleNamespace); /// /// Determines if a provided object is a JavscriptProxy Object and /// provides references to a Proxy's target and handler. /// /// /// Requires an active script context. /// If object is not a Proxy object the target and handler parameters are not touched. /// If nullptr is supplied for target or handler the function returns after /// setting the isProxy value. /// If the object is a revoked Proxy target and handler are set to JS_INVALID_REFERENCE. /// If it is a Proxy object that has not been revoked target and handler are set to the /// the object's target and handler. /// /// The object that may be a Proxy. /// Pointer to a Boolean - is the object a proxy? /// Pointer to a JsValueRef - the object's target. /// Pointer to a JsValueRef - the object's handler. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsGetProxyProperties( _In_ JsValueRef object, _Out_ bool* isProxy, _Out_opt_ JsValueRef* target, _Out_opt_ JsValueRef* handler); /// /// Parses a script and stores the generated parser state cache into a buffer which can be reused. /// /// /// /// JsSerializeParserState parses a script and then stores a cache of the parser state /// in a runtime-independent format. The parser state may be deserialized in any runtime along /// with the same script to skip the initial parse phase. /// /// /// Requires an active script context. /// /// /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// /// /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// /// /// The script to parse. /// The buffer to put the serialized parser state cache into. /// Encoding for the script. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsSerializeParserState( _In_ JsValueRef scriptVal, _Out_ JsValueRef *bufferVal, _In_ JsParseScriptAttributes parseAttributes); /// /// Deserializes the cache of initial parser state and (along with the same /// script source) executes the script and returns the result. /// /// /// /// Requires an active script context. /// /// /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// /// /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// /// /// The script to run. /// /// A cookie identifying the script that can be used by debuggable script contexts. /// /// The location the script came from /// Attribute mask for parsing the script /// /// A buffer containing a cache of the parser state generated by JsSerializeParserState. /// /// The result of the script, if any. This parameter can be null. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsRunScriptWithParserState( _In_ JsValueRef script, _In_ JsSourceContext sourceContext, _In_ JsValueRef sourceUrl, _In_ JsParseScriptAttributes parseAttributes, _In_ JsValueRef parserState, _Out_ JsValueRef * result); #endif // _CHAKRACOREBUILD #endif // _CHAKRACORE_H_ ================================================ FILE: include/ChakraCoreVersion.h ================================================ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once // NOTE: When changing this file, you may need to update the GUID in ByteCodeCacheReleaseFileVersion.h // Please update the GUID when: // * CHAKRA_CORE_VERSION_RELEASE is changed to 1 // * CHAKRA_CORE_VERSION_RELEASE is currently set to 1 and the bytecode changes // See notes below about ReleaseVersioningScheme. // -------------- // VERSION NUMBER // -------------- // ChakraCore version number definitions (used in ChakraCore binary metadata) #define CHAKRA_CORE_MAJOR_VERSION 1 #define CHAKRA_CORE_MINOR_VERSION 11 #define CHAKRA_CORE_PATCH_VERSION 24 #define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0. // ------------- // RELEASE FLAGS // ------------- // NOTE: CHAKRA_CORE_VERSION_PRERELEASE can only be set to 1 when // CHAKRA_CORE_VERSION_RELEASE is set to 1, or there is no effect. // Here are the meanings of the various combinations: // // RELEASE** PRERELEASE // DEVELOPMENT 0 0 // 0 1 # INVALID but identical to DEVELOPMENT // RELEASE** 1 0 # // PRERELEASE 1 1 // ** Release flags are not related to build type (e.g. x64_release) // // Unless otherwise noted, the code affected by these flags lies mostly in bin/CoreCommon.ver // // DEVELOPMENT: // * Uses EngineeringVersioningScheme (see lib/Runtime/ByteCode/ByteCodeSerializer.cpp) // * Sets file flag VS_FF_PRIVATEBUILD // * Adds "Private" to the file description // // RELEASE** and PRERELEASE (i.e. controlled by CHAKRA_CORE_VERSION_RELEASE flag): // * Uses ReleaseVersioningScheme (see lib/Runtime/ByteCode/ByteCodeSerializer.cpp) // // PRERELEASE (preparing for release but not yet ready to release): // * Sets file flag VS_FF_PRERELEASE // * Adds "Pre-release" to the file description // // RELEASE** (code is ready to release) // * Sets neither of the file flags noted above // * Does not add anything to the file description // ChakraCore RELEASE and PRERELEASE flags #define CHAKRA_CORE_VERSION_RELEASE 1 #define CHAKRA_CORE_VERSION_PRERELEASE 0 // Chakra RELEASE flag // Mostly redundant with CHAKRA_CORE_VERSION_RELEASE, // but semantically refers to Chakra rather than ChakraCore. #define CHAKRA_VERSION_RELEASE 0 ================================================ FILE: include/ChakraDebug.h ================================================ //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting Debugging API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to debug JavaScript. /// \file /// \brief The Chakra hosting debugging API. /// /// This file contains a flat C API layer. This is the API exported by ChakraCore.dll. #ifdef _MSC_VER #pragma once #endif // _MSC_VER #ifndef _CHAKRADEBUG_H_ #define _CHAKRADEBUG_H_ #ifdef _WIN32 //Other platforms already include and have this defined automatically typedef __int64 int64_t; typedef unsigned __int32 uint32_t; #endif /// /// Debug events reported from ChakraCore engine. /// typedef enum _JsDiagDebugEvent { /// /// Indicates a new script being compiled, this includes script, eval, new function. /// JsDiagDebugEventSourceCompile = 0, /// /// Indicates compile error for a script. /// JsDiagDebugEventCompileError = 1, /// /// Indicates a break due to a breakpoint. /// JsDiagDebugEventBreakpoint = 2, /// /// Indicates a break after completion of step action. /// JsDiagDebugEventStepComplete = 3, /// /// Indicates a break due to debugger statement. /// JsDiagDebugEventDebuggerStatement = 4, /// /// Indicates a break due to async break. /// JsDiagDebugEventAsyncBreak = 5, /// /// Indicates a break due to a runtime script exception. /// JsDiagDebugEventRuntimeException = 6 } JsDiagDebugEvent; /// /// Break on Exception attributes. /// typedef enum _JsDiagBreakOnExceptionAttributes { /// /// Don't break on any exception. /// JsDiagBreakOnExceptionAttributeNone = 0x0, /// /// Break on uncaught exception. /// JsDiagBreakOnExceptionAttributeUncaught = 0x1, /// /// Break on first chance exception. /// JsDiagBreakOnExceptionAttributeFirstChance = 0x2 } JsDiagBreakOnExceptionAttributes; /// /// Stepping types. /// typedef enum _JsDiagStepType { /// /// Perform a step operation to next statement. /// JsDiagStepTypeStepIn = 0, /// /// Perform a step out from the current function. /// JsDiagStepTypeStepOut = 1, /// /// Perform a single step over after a debug break if the next statement is a function call, else behaves as a stepin. /// JsDiagStepTypeStepOver = 2, /// /// Perform a single step back to the previous statement (only applicable in TTD mode). /// JsDiagStepTypeStepBack = 3, /// /// Perform a reverse continue operation (only applicable in TTD mode). /// JsDiagStepTypeReverseContinue = 4, /// /// Perform a forward continue operation. Clears any existing step value. /// JsDiagStepTypeContinue = 5 } JsDiagStepType; /// /// User implemented callback routine for debug events. /// /// /// Use JsDiagStartDebugging to register the callback. /// /// The type of JsDiagDebugEvent event. /// Additional data related to the debug event. /// The state passed to JsDiagStartDebugging. typedef void (CHAKRA_CALLBACK * JsDiagDebugEventCallback)(_In_ JsDiagDebugEvent debugEvent, _In_ JsValueRef eventData, _In_opt_ void* callbackState); /// /// Starts debugging in the given runtime. /// /// Runtime to put into debug mode. /// Registers a callback to be called on every JsDiagDebugEvent. /// User provided state that will be passed back to the callback. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The runtime should be active on the current thread and should not be in debug state. /// CHAKRA_API JsDiagStartDebugging( _In_ JsRuntimeHandle runtimeHandle, _In_ JsDiagDebugEventCallback debugEventCallback, _In_opt_ void* callbackState); /// /// Stops debugging in the given runtime. /// /// Runtime to stop debugging. /// User provided state that was passed in JsDiagStartDebugging. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The runtime should be active on the current thread and in debug state. /// CHAKRA_API JsDiagStopDebugging( _In_ JsRuntimeHandle runtimeHandle, _Out_opt_ void** callbackState); /// /// Request the runtime to break on next JavaScript statement. /// /// Runtime to request break. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The runtime should be in debug state. This API can be called from another runtime. /// CHAKRA_API JsDiagRequestAsyncBreak( _In_ JsRuntimeHandle runtimeHandle); /// /// List all breakpoints in the current runtime. /// /// Array of breakpoints. /// /// /// [{ /// "breakpointId" : 1, /// "scriptId" : 1, /// "line" : 0, /// "column" : 62 /// }] /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagGetBreakpoints( _Out_ JsValueRef *breakpoints); /// /// Sets breakpoint in the specified script at give location. /// /// Id of script from JsDiagGetScripts or JsDiagGetSource to put breakpoint. /// 0 based line number to put breakpoint. /// 0 based column number to put breakpoint. /// Breakpoint object with id, line and column if success. /// /// /// { /// "breakpointId" : 1, /// "line" : 2, /// "column" : 4 /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagSetBreakpoint( _In_ unsigned int scriptId, _In_ unsigned int lineNumber, _In_ unsigned int columnNumber, _Out_ JsValueRef *breakpoint); /// /// Remove a breakpoint. /// /// Breakpoint id returned from JsDiagSetBreakpoint. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagRemoveBreakpoint( _In_ unsigned int breakpointId); /// /// Sets break on exception handling. /// /// Runtime to set break on exception attributes. /// Mask of JsDiagBreakOnExceptionAttributes to set. /// /// /// If this API is not called the default value is set to JsDiagBreakOnExceptionAttributeUncaught in the runtime. /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The runtime should be in debug state. This API can be called from another runtime. /// CHAKRA_API JsDiagSetBreakOnException( _In_ JsRuntimeHandle runtimeHandle, _In_ JsDiagBreakOnExceptionAttributes exceptionAttributes); /// /// Gets break on exception setting. /// /// Runtime from which to get break on exception attributes, should be in debug mode. /// Mask of JsDiagBreakOnExceptionAttributes. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The runtime should be in debug state. This API can be called from another runtime. /// CHAKRA_API JsDiagGetBreakOnException( _In_ JsRuntimeHandle runtimeHandle, _Out_ JsDiagBreakOnExceptionAttributes* exceptionAttributes); /// /// Sets the step type in the runtime after a debug break. /// /// /// Requires to be at a debug break. /// /// Type of JsDiagStepType. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagSetStepType( _In_ JsDiagStepType stepType); /// /// Gets list of scripts. /// /// Array of script objects. /// /// /// [{ /// "scriptId" : 2, /// "fileName" : "c:\\Test\\Test.js", /// "lineCount" : 4, /// "sourceLength" : 111 /// }, { /// "scriptId" : 3, /// "parentScriptId" : 2, /// "scriptType" : "eval code", /// "lineCount" : 1, /// "sourceLength" : 12 /// }] /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagGetScripts( _Out_ JsValueRef *scriptsArray); /// /// Gets source for a specific script identified by scriptId from JsDiagGetScripts. /// /// Id of the script. /// Source object. /// /// /// { /// "scriptId" : 1, /// "fileName" : "c:\\Test\\Test.js", /// "lineCount" : 12, /// "sourceLength" : 15154, /// "source" : "var x = 1;" /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagGetSource( _In_ unsigned int scriptId, _Out_ JsValueRef *source); /// /// Gets the source information for a function object. /// /// JavaScript function. /// Function position - scriptId, start line, start column, line number of first statement, column number of first statement. /// /// /// { /// "scriptId" : 1, /// "fileName" : "c:\\Test\\Test.js", /// "line" : 1, /// "column" : 2, /// "firstStatementLine" : 6, /// "firstStatementColumn" : 0 /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// This API can be called when runtime is at a break or running. /// CHAKRA_API JsDiagGetFunctionPosition( _In_ JsValueRef function, _Out_ JsValueRef *functionPosition); /// /// Gets the stack trace information. /// /// Stack trace information. /// /// /// [{ /// "index" : 0, /// "scriptId" : 2, /// "line" : 3, /// "column" : 0, /// "sourceLength" : 9, /// "sourceText" : "var x = 1", /// "functionHandle" : 1 /// }] /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagGetStackTrace( _Out_ JsValueRef *stackTrace); /// /// Gets the list of properties corresponding to the frame. /// /// Index of stack frame from JsDiagGetStackTrace. /// Object of properties array (properties, scopes and globals). /// /// /// propertyAttributes is a bit mask of /// NONE = 0x1, /// HAVE_CHILDRENS = 0x2, /// READ_ONLY_VALUE = 0x4, /// IN_TDZ = 0x8, /// /// /// { /// "thisObject": { /// "name": "this", /// "type" : "object", /// "className" : "Object", /// "display" : "{...}", /// "propertyAttributes" : 1, /// "handle" : 306 /// }, /// "exception" : { /// "name" : "{exception}", /// "type" : "object", /// "display" : "'a' is undefined", /// "className" : "Error", /// "propertyAttributes" : 1, /// "handle" : 307 /// } /// "arguments" : { /// "name" : "arguments", /// "type" : "object", /// "display" : "{...}", /// "className" : "Object", /// "propertyAttributes" : 1, /// "handle" : 190 /// }, /// "returnValue" : { /// "name" : "[Return value]", /// "type" : "undefined", /// "propertyAttributes" : 0, /// "handle" : 192 /// }, /// "functionCallsReturn" : [{ /// "name" : "[foo1 returned]", /// "type" : "number", /// "value" : 1, /// "propertyAttributes" : 2, /// "handle" : 191 /// } /// ], /// "locals" : [], /// "scopes" : [{ /// "index" : 0, /// "handle" : 193 /// } /// ], /// "globals" : { /// "handle" : 194 /// } /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagGetStackProperties( _In_ unsigned int stackFrameIndex, _Out_ JsValueRef *properties); /// /// Gets the list of children of a handle. /// /// Handle of object. /// 0-based from count of properties, usually 0. /// Number of properties to return. /// Array of properties. /// Handle should be from objects returned from call to JsDiagGetStackProperties. /// For scenarios where object have large number of properties totalCount can be used to control how many properties are given. /// /// /// { /// "totalPropertiesOfObject": 10, /// "properties" : [{ /// "name" : "__proto__", /// "type" : "object", /// "display" : "{...}", /// "className" : "Object", /// "propertyAttributes" : 1, /// "handle" : 156 /// } /// ], /// "debuggerOnlyProperties" : [{ /// "name" : "[Map]", /// "type" : "string", /// "value" : "size = 0", /// "propertyAttributes" : 2, /// "handle" : 157 /// } /// ] /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagGetProperties( _In_ unsigned int objectHandle, _In_ unsigned int fromCount, _In_ unsigned int totalCount, _Out_ JsValueRef *propertiesObject); /// /// Gets the object corresponding to handle. /// /// Handle of object. /// Object corresponding to the handle. /// /// /// { /// "scriptId" : 24, /// "line" : 1, /// "column" : 63, /// "name" : "foo", /// "type" : "function", /// "handle" : 2 /// } /// /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagGetObjectFromHandle( _In_ unsigned int objectHandle, _Out_ JsValueRef *handleObject); /// /// Evaluates an expression on given frame. /// /// /// Javascript String or ArrayBuffer (incl. ExternalArrayBuffer). /// /// Index of stack frame on which to evaluate the expression. /// /// Defines how `expression` (JsValueRef) should be parsed. /// - `JsParseScriptAttributeNone` when `expression` is a Utf8 encoded ArrayBuffer and/or a Javascript String (encoding independent) /// - `JsParseScriptAttributeArrayBufferIsUtf16Encoded` when `expression` is Utf16 Encoded ArrayBuffer /// - `JsParseScriptAttributeLibraryCode` has no use for this function and has similar effect with `JsParseScriptAttributeNone` /// /// Forces the result to contain the raw value of the expression result. /// Result of evaluation. /// /// /// evalResult when evaluating 'this' and return is JsNoError /// { /// "name" : "this", /// "type" : "object", /// "className" : "Object", /// "display" : "{...}", /// "propertyAttributes" : 1, /// "handle" : 18 /// } /// /// evalResult when evaluating a script which throws JavaScript error and return is JsErrorScriptException /// { /// "name" : "a.b.c", /// "type" : "object", /// "className" : "Error", /// "display" : "'a' is undefined", /// "propertyAttributes" : 1, /// "handle" : 18 /// } /// /// /// /// The code JsNoError if the operation succeeded, evalResult will contain the result /// The code JsErrorScriptException if evaluate generated a JavaScript exception, evalResult will contain the error details /// Other error code for invalid parameters or API was not called at break /// /// /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// CHAKRA_API JsDiagEvaluate( _In_ JsValueRef expression, _In_ unsigned int stackFrameIndex, _In_ JsParseScriptAttributes parseAttributes, _In_ bool forceSetValueProp, _Out_ JsValueRef *evalResult); ///////////////////// /// /// TimeTravel move options as bit flag enum. /// typedef enum _JsTTDMoveModes { /// /// Indicates no special actions needed for move. /// JsTTDMoveNone = 0x0, /// /// Indicates that we want to move to the first event. /// JsTTDMoveFirstEvent = 0x1, /// /// Indicates that we want to move to the last event. /// JsTTDMoveLastEvent = 0x2, /// /// Indicates that we want to move to the kth event -- top 32 bits are event count. /// JsTTDMoveKthEvent = 0x4, /// /// Indicates if we are doing the scan for a continue operation /// JsTTDMoveScanIntervalForContinue = 0x10, /// /// Indicates if we are doing the scan for a continue operation and are in the time-segment where the active breakpoint was /// JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment = 0x20, /// /// Indicates if we want to set break on entry or just run and let something else trigger breakpoints. /// JsTTDMoveBreakOnEntry = 0x100 } JsTTDMoveMode; /// /// A handle for URI's that TTD information is written to/read from. /// typedef void* JsTTDStreamHandle; /// /// TTD API -- may change in future versions: /// Construct a JsTTDStreamHandle that will be used to read/write the event log portion of the TTD data based on the uri /// provided by JsTTDInitializeUriCallback. /// /// /// Exactly one of read or write will be set to true. /// /// The length of the uri array that the host passed in for storing log info. /// The URI that the host passed in for storing log info. /// The length of the ascii name array that the host passed in for storing log info. /// An optional ascii string giving a unique name to the resource that the JsTTDStreamHandle will be created for. /// If the handle should be opened for reading. /// If the handle should be opened for writing. /// A JsTTDStreamHandle opened in read/write mode as specified. typedef JsTTDStreamHandle (CHAKRA_CALLBACK *TTDOpenResourceStreamCallback)(_In_ size_t uriLength, _In_reads_(uriLength) const char* uri, _In_ size_t asciiNameLength, _In_reads_(asciiNameLength) const char* asciiResourceName, _In_ bool read, _In_ bool write); /// /// TTD API -- may change in future versions: /// A callback for reading data from a handle. /// /// The JsTTDStreamHandle to read the data from. /// The buffer to place the data into. /// The max number of bytes that should be read. /// The actual number of bytes read and placed in the buffer. /// true if the read was successful false otherwise. typedef bool (CHAKRA_CALLBACK *JsTTDReadBytesFromStreamCallback)(_In_ JsTTDStreamHandle handle, _Out_writes_(size) byte* buff, _In_ size_t size, _Out_ size_t* readCount); /// /// TTD API -- may change in future versions: /// A callback for writing data to a handle. /// /// The JsTTDStreamHandle to write the data to. /// The buffer to copy the data from. /// The max number of bytes that should be written. /// The actual number of bytes written to the HANDLE. /// true if the write was successful false otherwise. typedef bool (CHAKRA_CALLBACK *JsTTDWriteBytesToStreamCallback)(_In_ JsTTDStreamHandle handle, _In_reads_(size) const byte* buff, _In_ size_t size, _Out_ size_t* writtenCount); /// /// TTD API -- may change in future versions: /// Flush and close the stream represented by the HANDLE as needed. /// /// /// Exactly one of read or write will be set to true. /// /// The JsTTDStreamHandle to close. /// If the handle was opened for reading. /// If the handle was opened for writing. typedef void (CHAKRA_CALLBACK *JsTTDFlushAndCloseStreamCallback)(_In_ JsTTDStreamHandle handle, _In_ bool read, _In_ bool write); /// /// TTD API -- may change in future versions: /// Creates a new runtime in Record Mode. /// /// The attributes of the runtime to be created. /// A flag to enable debugging during record. /// The interval to wait between snapshots (measured in millis). /// The amount of history to maintain before discarding -- measured in number of snapshots and controls how far back in time a trace can be reversed. /// The TTDOpenResourceStreamCallback function for generating a JsTTDStreamHandle to read/write serialized data. /// The JsTTDWriteBytesToStreamCallback function for writing bytes to a JsTTDStreamHandle. /// The JsTTDFlushAndCloseStreamCallback function for flushing and closing a JsTTDStreamHandle as needed. /// The thread service for the runtime. Can be null. /// The runtime created. /// /// See JsCreateRuntime for additional information. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsTTDCreateRecordRuntime( _In_ JsRuntimeAttributes attributes, _In_ bool enableDebugging, _In_ size_t snapInterval, _In_ size_t snapHistoryLength, _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDWriteBytesToStreamCallback writeBytesToStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream, _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime); /// /// TTD API -- may change in future versions: /// Creates a new runtime in Debug Mode. /// /// The attributes of the runtime to be created. /// The uri where the recorded Time-Travel data should be loaded from. /// A flag to enable additional debugging operation support during replay. /// The TTDOpenResourceStreamCallback function for generating a JsTTDStreamHandle to read/write serialized data. /// The JsTTDReadBytesFromStreamCallback function for reading bytes from a JsTTDStreamHandle. /// The JsTTDFlushAndCloseStreamCallback function for flushing and closing a JsTTDStreamHandle as needed. /// The thread service for the runtime. Can be null. /// The runtime created. /// /// See JsCreateRuntime for additional information. /// /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsTTDCreateReplayRuntime( _In_ JsRuntimeAttributes attributes, _In_reads_(infoUriCount) const char* infoUri, _In_ size_t infoUriCount, _In_ bool enableDebugging, _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDReadBytesFromStreamCallback readBytesFromStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream, _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime); /// /// TTD API -- may change in future versions: /// Creates a script context that takes the TTD mode from the log or explicitly is not in TTD mode (regular takes mode from currently active script). /// /// The runtime the script context is being created in. /// Set to true to use runtime TTD mode false to explicitly be non-TTD context. /// The created script context. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsTTDCreateContext( _In_ JsRuntimeHandle runtimeHandle, _In_ bool useRuntimeTTDMode, _Out_ JsContextRef *newContext); /// /// TTD API -- may change in future versions: /// Notify the time-travel system that a context has been identified as dead by the gc (and is being de-allocated). /// /// The script context that is now dead. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. /// CHAKRA_API JsTTDNotifyContextDestroy( _In_ JsContextRef context); /// /// TTD API -- may change in future versions: /// Start Time-Travel record or replay at next turn of event loop. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDStart(); /// /// TTD API -- may change in future versions: /// Stop Time-Travel record or replay. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDStop(); /// /// TTD API -- may change in future versions: /// Pause Time-Travel recording before executing code on behalf of debugger or other diagnostic/telemetry. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDPauseTimeTravelBeforeRuntimeOperation(); /// /// TTD API -- may change in future versions: /// ReStart Time-Travel recording after executing code on behalf of debugger or other diagnostic/telemetry. /// /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDReStartTimeTravelAfterRuntimeOperation(); /// /// TTD API -- may change in future versions: /// Notify the Js runtime we are at a safe yield point in the event loop (i.e. no locals on the stack and we can process as desired). /// /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDNotifyYield(); /// /// TTD API -- may change in future versions: /// Notify the TTD runtime that we are doing a weak add on a reference (we may use this in external API calls and the release will happen in a GC callback). /// /// The value we are adding the ref to. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDNotifyLongLivedReferenceAdd(_In_ JsValueRef value); /// /// TTD API -- may change in future versions: /// Notify the Js runtime the host is aborting the process and what the status code is. /// /// The exit status code. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDHostExit(_In_ int statusCode); /// /// TTD API -- may change in future versions: /// Notify the event log that the contents of one buffer have been copied to a second buffer. /// /// The buffer that was written into. /// The first index modified. /// The buffer that was copied from. /// The first index copied. /// The number of bytes copied. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDRawBufferCopySyncIndirect( _In_ JsValueRef dst, _In_ size_t dstIndex, _In_ JsValueRef src, _In_ size_t srcIndex, _In_ size_t count); /// /// TTD API -- may change in future versions: /// Notify the event log that the contents of a naked byte* buffer passed to the host have been modified synchronously. /// /// The buffer that was modified. /// The first index modified. /// The number of bytes written. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDRawBufferModifySyncIndirect( _In_ JsValueRef buffer, _In_ size_t index, _In_ size_t count); /// /// TTD API -- may change in future versions: /// Get info for notifying the TTD system that a raw buffer it shares with the host has been modified. /// /// The array buffer we want to monitor for contents modification. /// The first position in the buffer that may be modified. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDRawBufferAsyncModificationRegister( _In_ JsValueRef instance, _In_ byte* initialModPos); /// /// TTD API -- may change in future versions: /// Notify the event log that the contents of a naked byte* buffer passed to the host have been modified asynchronously. /// /// One past the last modified position in the buffer. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDRawBufferAsyncModifyComplete( _In_ byte* finalModPos); /// /// TTD API -- may change in future versions: /// A check for unimplemented TTD actions in the host. /// This API is a TEMPORARY API while we complete the implementation of TTD support in the Node host and will be deleted once that is complete. /// /// The message to print if we should be catching this as a TTD operation. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDCheckAndAssertIfTTDRunning( _In_ const char* msg); /// /// TTD API -- may change in future versions: /// Before calling JsTTDMoveToTopLevelEvent (which inflates a snapshot and replays) check to see if we want to reset the script context. /// We reset the script context if the move will require inflating from a different snapshot that the last one. /// /// The runtime handle that the script is executing in. /// Flags controlling the way the move it performed and how other parameters are interpreted. /// When moveMode == JsTTDMoveKthEvent indicates which event, otherwise this parameter is ignored. /// The event time we want to move to or -1 if not relevant. /// Out parameter with the event time of the snapshot that we should inflate from. /// Optional Out parameter with the snapshot time following the event. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDGetSnapTimeTopLevelEventMove( _In_ JsRuntimeHandle runtimeHandle, _In_ JsTTDMoveMode moveMode, _In_opt_ uint32_t kthEvent, _Inout_ int64_t* targetEventTime, _Out_ int64_t* targetStartSnapTime, _Out_opt_ int64_t* targetEndSnapTime); /// /// TTD API -- may change in future versions: /// Get the snapshot interval that bounds the target event time. /// /// The runtime handle that the script is executing in. /// The event time we want to get the interval for. /// The snapshot time that comes before the desired event. /// The snapshot time that comes after the desired event (-1 if the leg ends before a snapshot appears). /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDGetSnapShotBoundInterval( _In_ JsRuntimeHandle runtimeHandle, _In_ int64_t targetEventTime, _Out_ int64_t* startSnapTime, _Out_ int64_t* endSnapTime); /// /// TTD API -- may change in future versions: /// Get the snapshot interval that precedes the one given by currentSnapStartTime (or -1 if there is no such interval). /// /// The runtime handle that the script is executing in. /// The current snapshot interval start time. /// The resulting previous snapshot interval start time or -1 if no such time. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDGetPreviousSnapshotInterval( _In_ JsRuntimeHandle runtimeHandle, _In_ int64_t currentSnapStartTime, _Out_ int64_t* previousSnapTime); /// /// TTD API -- may change in future versions: /// During debug operations some additional information is populated during replay. This runs the code between the given /// snapshots to populate this information which may be needed by the debugger to determine time-travel jump targets. /// /// The runtime handle that the script is executing in. ///The snapshot time that we will start executing from.< / param> ///The snapshot time that we will stop at (or -1 if we want to run to the end).< / param> /// Additional flags for controling how the move is done. /// The updated target event time set according to the moveMode (-1 if not found). /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDPreExecuteSnapShotInterval( _In_ JsRuntimeHandle runtimeHandle, _In_ int64_t startSnapTime, _In_ int64_t endSnapTime, _In_ JsTTDMoveMode moveMode, _Out_ int64_t* newTargetEventTime); /// /// TTD API -- may change in future versions: /// Move to the given top-level call event time (assuming JsTTDPrepContextsForTopLevelEventMove) was called previously to reset any script contexts. /// This also computes the ready-to-run snapshot if needed. /// /// The runtime handle that the script is executing in. /// Additional flags for controling how the move is done. /// The event time that we will start executing from to move to the given target time. /// The event that we want to move to. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDMoveToTopLevelEvent( _In_ JsRuntimeHandle runtimeHandle, _In_ JsTTDMoveMode moveMode, _In_ int64_t snapshotTime, _In_ int64_t eventTime); /// /// TTD API -- may change in future versions: /// Execute from the current point in the log to the end returning the error code. /// /// Additional flags for controling how the move is done. /// The event time that we should move to next or notification (-1) that replay has ended. /// /// If the debugger requested an abort the code is JsNoError -- rootEventTime is the target event time we need to move to and re - execute from. /// If we aborted at the end of the replay log the code is JsNoError -- rootEventTime is -1. /// If there was an unhandled script exception the code is JsErrorCategoryScript. /// CHAKRA_API JsTTDReplayExecution( _Inout_ JsTTDMoveMode* moveMode, _Out_ int64_t* rootEventTime); /// /// TTD API -- may change in future versions: /// Enable or disable autotrace ability from JsRT. /// /// True to enable autotracing false to disable it. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDDiagSetAutoTraceStatus( _In_ bool status ); /// /// TTD API -- may change in future versions: /// A way for the debugger to programatically write a trace when it is at a breakpoint. /// /// The URI that the log should be written into. /// The length of the uri array that the host passed in for storing log info. /// The code JsNoError if the operation succeeded, a failure code otherwise. CHAKRA_API JsTTDDiagWriteLog( _In_reads_(uriLength) const char* uri, _In_ size_t uriLength ); #endif // _CHAKRADEBUG_H_ ================================================ FILE: packages.config ================================================  ================================================ FILE: samples/HostSample/ChakraCoreHostMainData.dfm ================================================ object DataModuleMain: TDataModuleMain OldCreateOrder = False OnCreate = DataModuleCreate OnDestroy = DataModuleDestroy Height = 265 Width = 368 end ================================================ FILE: samples/HostSample/ChakraCoreHostMainData.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit ChakraCoreHostMainData; interface {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cwstring, {$endif}{$endif} {$ifdef WINDOWS} Windows, {$endif} SysUtils, Classes, {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Compat, ChakraCommon, ChakraCore, ChakraCoreUtils, ChakraCoreClasses, Console; type { TDataModuleMain } TDataModuleMain = class(TDataModule) procedure DataModuleCreate(Sender: TObject); procedure DataModuleDestroy(Sender: TObject); private FBaseDir: UnicodeString; FConsole: TConsole; FContext: TChakraCoreContext; FRuntime: TChakraCoreRuntime; FUseAnsiColors: Boolean; procedure ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel = ilNone); procedure ContextActivate(Sender: TObject); procedure ContextLoadModule(Sender: TObject; Module: TChakraModule); procedure ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); public procedure Execute(const ScriptFileNames: array of UnicodeString); property BaseDir: UnicodeString read FBaseDir; property Console: TConsole read FConsole; property Context: TChakraCoreContext read FContext; property Runtime: TChakraCoreRuntime read FRuntime; property UseAnsiColors: Boolean read FUseAnsiColors write FUseAnsiColors; end; implementation {$R *.dfm} function LoadFile(const FileName: UnicodeString): UnicodeString; var FileStream: TFileStream; S: UTF8String; begin Result := ''; FileStream := TFileStream.Create(FileName, fmOpenRead); try if FileStream.Size = 0 then Exit; SetLength(S, FileStream.Size); FileStream.Read(S[1], FileStream.Size); Result := UTF8ToString(S); finally FileStream.Free; end; end; function PostTimedTask(Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer; RepeatCount: Integer): JsValueRef; var DataModule: TDataModuleMain absolute CallbackState; AMessage: TTaskMessage; Delay: Cardinal; FuncArgs: array of JsValueRef; I: Integer; begin Result := JsUndefinedValue; if ArgCount < 2 then // thisarg, function to call, optional: delay, function args raise Exception.Create('Invalid arguments'); if ArgCount >= 3 then Delay := JsNumberToInt(Args^[2]) else Delay := 0; if ArgCount >= 4 then begin SetLength(FuncArgs, ArgCount - 3); for I := 0 to ArgCount - 4 do FuncArgs[I] := Args^[I + 3]; end; AMessage := TTaskMessage.Create(DataModule.Context, Args^[1], Args^[0], FuncArgs, Delay, RepeatCount); try DataModule.Context.PostMessage(AMessage); except AMessage.Free; raise; end; end; function SetInterval_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := PostTimedTask(Args, ArgCount, CallbackState, -1); // repeat endlessly end; function SetTimeout_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := PostTimedTask(Args, ArgCount, CallbackState, 1); // run once end; type THackPromiseMessage = class(TPromiseMessage); TDummyPromiseThread = class(TThread) private FMessage: TPromiseMessage; FTimeout: Cardinal; FValue: JsValueRef; protected procedure Execute; override; public constructor Create(AMessage: TPromiseMessage; ATimeout: Cardinal); end; { TTestPromiseThread } procedure TDummyPromiseThread.Execute; begin Sleep(FTimeout); THackPromiseMessage(FMessage).SetStatus(psResolved, FValue); end; constructor TDummyPromiseThread.Create(AMessage: TPromiseMessage; ATimeout: Cardinal); begin FMessage := AMessage; FTimeout := ATimeout; FValue := StringToJsString('Success!'); JsAddRef(FValue); FreeOnTerminate := True; inherited Create(False); end; function TestPromise_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var DataModule: TDataModuleMain absolute CallbackState; AMessage: TPromiseMessage; ResolveTask, RejectTask: JsValueRef; begin if ArgCount <> 2 then // thisarg, timeout raise Exception.Create('Invalid arguments'); JsCreatePromise(Result, ResolveTask, RejectTask); AMessage := TPromiseMessage.Create(DataModule.Context, Args^[0], ResolveTask, RejectTask); try TDummyPromiseThread.Create(AMessage, JsNumberToInt(Args^[1])); DataModule.Context.PostMessage(AMessage); except AMessage.Free; raise; end; end; procedure TDataModuleMain.ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel); const StartBlocks: array[TInfoLevel] of RawByteString = ('', #$1b'[32;1m', #$1b'[33;1m', #$1b'[31;1m'); EndBlocks: array[Boolean] of RawByteString = ('', #$1b'[0m'); {$ifdef WINDOwS} BackgroundMask = $F0; TextColors: array[TInfoLevel] of Word = (0, FOREGROUND_GREEN or FOREGROUND_INTENSITY, FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY, FOREGROUND_RED or FOREGROUND_INTENSITY); {$endif} var {$ifdef WINDOWS} Info: TConsoleScreenBufferInfo; {$endif} S: UTF8String; begin S := UTF8Encode(Text); {$ifdef WINDOWS} if UseAnsiColors then Writeln(StartBlocks[Level], S, EndBlocks[Level <> ilNone]) else begin if (Level = ilNone) or not GetConsoleScreenBufferInfo(TTextRec(Output).Handle, Info) then begin Writeln(S); Exit; end; SetConsoleTextAttribute(TTextRec(Output).Handle, Info.wAttributes and BackgroundMask or TextColors[Level]); try Writeln(S); finally SetConsoleTextAttribute(TTextRec(Output).Handle, Info.wAttributes); end; end; {$else} Writeln(StartBlocks[Level], S, EndBlocks[Level <> ilNone]); {$endif} end; procedure TDataModuleMain.ContextActivate(Sender: TObject); begin // expose additional functions JsSetCallback(FContext.Global, 'setTimeout', @SetTimeout_Callback, Self, True); JsSetCallback(FContext.Global, 'setInterval', @SetInterval_Callback, Self, True); JsSetCallback(FContext.Global, 'testPromise', @TestPromise_Callback, Self, True); // project TConsole class so scripts can create instances, e.g. var c = new Console(); TConsole.Project; // expose global.console FConsole := TConsole.Create; JsSetProperty(FContext.Global, 'console', FConsole.Instance); end; procedure TDataModuleMain.ContextLoadModule(Sender: TObject; Module: TChakraModule); var ModuleFileName: UnicodeString; begin ModuleFileName := IncludeTrailingPathDelimiter(FBaseDir) + ChangeFileExt(Module.Name, UnicodeString('.js')); if FileExists(ModuleFileName) then begin Module.Parse(LoadFile(ModuleFileName)); Module.URL := WideFormat('file://%s/%s', [ChangeFileExt(ExtractFileName(ParamStr(0)), UnicodeString('')), ChangeFileExt(Module.Name, UnicodeString('.js'))]); end; end; procedure TDataModuleMain.ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); begin if NativeObject is TConsole then TConsole(NativeObject).OnLog := ConsoleLog; end; procedure TDataModuleMain.DataModuleCreate(Sender: TObject); begin try FRuntime := TChakraCoreRuntime.Create([ccroEnableExperimentalFeatures, ccroDispatchSetExceptionsToDebugger]); FContext := TChakraCoreContext.Create(FRuntime); FContext.OnActivate := ContextActivate; FContext.OnLoadModule := ContextLoadModule; FContext.OnNativeObjectCreated := ContextNativeObjectCreated; except FreeAndNil(FConsole); FreeAndNil(FContext); FreeAndNil(FRuntime); raise; end; end; procedure TDataModuleMain.DataModuleDestroy(Sender: TObject); begin FreeAndNil(FConsole); FreeAndNil(FContext); FreeAndNil(FRuntime); end; procedure TDataModuleMain.Execute(const ScriptFileNames: array of UnicodeString); var I: Integer; begin for I := Low(ScriptFileNames) to High(ScriptFileNames) do begin FBaseDir := ExtractFilePath(ScriptFileNames[I]); FContext.RunScript(LoadFile(ScriptFilenames[I]), UnicodeString(ExtractFileName(ScriptFileNames[I]))); end; end; end. ================================================ FILE: samples/HostSample/ChakraCoreHostSample.XE.dproj ================================================  {2b63895c-8001-41eb-a2d0-6815b28b3222} ChakraCoreHostSample.dpr Debug DCC32 12.3 True Win32 Console None true true Base true true Base true ..\..\bin\$(Platform)\$(Config)\ChakraCoreHostSample.exe ..\..\bin\$(Platform)\$(Config) ..\..\lib\$(Platform)\$(Config) 00400000 vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) x86 ..\..\src;$(DCC_UnitSearchPath) false true false 1 false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource
DataModuleMain
TDataModule
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication ChakraCoreHostSample.dpr ..\..\..\samples\HostSample\scripts\main.js True False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 ChakraCoreHostSample © 2021 Ondrej Kelle ChakraCoreHostSample.exe chakracore-delphi 1.0.0.0 True 12
================================================ FILE: samples/HostSample/ChakraCoreHostSample.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=0 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\..\bin\Win32\Debug UnitOutputDir=..\..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\..\src Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams=..\..\..\samples\HostSample\scripts\main.js HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=ChakraCoreHostSample LegalCopyright=© 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=ChakraCoreHostSample.exe ProductName=chakracore-delphi ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: samples/HostSample/ChakraCoreHostSample.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program ChakraCoreHostSample; {$APPTYPE CONSOLE} {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cthreads, {$endif}{$endif} SysUtils, Compat, ChakraCoreVersion, ChakraCoreUtils, ChakraCoreHostMainData in 'ChakraCoreHostMainData.pas' {DataModuleMain: TDataModule}; {$R *.res} procedure ShowInfo; begin Writeln(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); Writeln(Format('Built with %s', [GetBuildInfoString])); Writeln(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); Writeln; end; type UnicodeStringDynArray = array of UnicodeString; function ParamStrings: UnicodeStringDynArray; var I: Integer; begin Result := nil; SetLength(Result, ParamCount); for I := 1 to ParamCount do Result[I - 1] := UnicodeString(ParamStr(I)); end; procedure Main; var DataModule: TDataModuleMain; begin ShowInfo; DataModule := TDataModuleMain.Create(nil); try DataModule.Execute(ParamStrings); finally DataModule.Free; end; end; begin {$ifdef DELPHI2006_UP} ReportMemoryLeaksOnShutdown := True; {$endif} try Main; except on E: EChakraCoreScript do begin ExitCode := 1; Writeln(Format('%s (%d, %d): [%s] %s', [E.ScriptURL, E.Line + 1, E.Column + 1, E.ClassName, E.Message])); end; on E: Exception do begin ExitCode := 1; Writeln(Format('[%s] %s', [E.ClassName, E.Message])); end; end; end. ================================================ FILE: samples/HostSample/ChakraCoreHostSample.lpi ================================================ ================================================ FILE: samples/HostSample/Console.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit Console; interface {$include common.inc} uses SysUtils, Classes, {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Compat, ChakraCommon, ChakraCoreUtils, ChakraCoreClasses; type TInfoLevel = (ilNone, ilInfo, ilWarn, ilError); TConsoleLogEvent = procedure (Sender: TObject; const Text: UnicodeString; Level: TInfoLevel = ilNone) of object; { TConsole } TConsole = class(TNativeObject) private FOnLog: TConsoleLogEvent; function Assert(Args: PJsValueRef; ArgCount: Word): JsValueRef; function LogError(Args: PJsValueRef; ArgCount: Word): JsValueRef; function LogInfo(Args: PJsValueRef; ArgCount: Word): JsValueRef; function LogNone(Args: PJsValueRef; ArgCount: Word): JsValueRef; function LogWarn(Args: PJsValueRef; ArgCount: Word): JsValueRef; protected procedure DoLog(const Text: UnicodeString; Level: TInfoLevel = ilNone); virtual; class procedure RegisterMethods(AInstance: JsValueRef); override; public function Log(Args: PJsValueRef; ArgCount: Word; Level: TInfoLevel = ilNone): JsValueRef; overload; function Log(const Args: array of JsValueRef; Level: TInfoLevel = ilNone): JsValueRef; overload; property OnLog: TConsoleLogEvent read FOnLog write FOnLog; end; implementation function FmtSpecPos(S: PWideChar): PWideChar; var P: PWideChar; begin Result := nil; P := WStrPos(S, '%'); while Assigned(P) do begin case (P + 1)^ of #0: Break; 'd', 'i', 'f', 'o', 's': begin Result := P; Break; end; '%': begin Inc(P); if P^ = #0 then Break; end; end; P := WStrPos(P + 1, '%'); end; end; { TConsole private } function TConsole.Assert(Args: PJsValueRef; ArgCount: Word): JsValueRef; var ArgCondition: JsValueRef; SMessage: UnicodeString; begin Result := JsUndefinedValue; if ArgCount < 1 then Exit; SMessage := 'Assertion failed'; // arg 1 = condition (boolean) ArgCondition := Args^; if (JsGetValueType(ArgCondition) <> JsBoolean) then raise Exception.Create('condition passed to console.assert not a boolean'); Inc(Args); Dec(ArgCount); if (JsBooleanToBoolean(ArgCondition)) then // assertion passed Exit; if ArgCount = 0 then // no message/data DoLog(SMessage, ilError) else Log(Args, ArgCount, ilError); end; function TConsole.LogError(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := Log(Args, ArgCount, ilError); end; function TConsole.LogInfo(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := Log(Args, ArgCount, ilInfo); end; function TConsole.LogNone(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := Log(Args, ArgCount, ilNone); end; function TConsole.LogWarn(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := Log(Args, ArgCount, ilWarn); end; { TConsole protected } procedure TConsole.DoLog(const Text: UnicodeString; Level: TInfoLevel); begin if Assigned(FOnLog) then FOnLog(Self, Text, Level); end; { TConsole public } function TConsole.Log(Args: PJsValueRef; ArgCount: Word; Level: TInfoLevel): JsValueRef; var FirstArg, S, SCopy: UnicodeString; P, PPrev: PWideChar; Arg: PJsValueRef; I, ArgIndex: Integer; begin Result := JsUndefinedValue; if not Assigned(Args) then Exit; S := ''; P := nil; PPrev := nil; Arg := Args; ArgIndex := 0; if Assigned(Args) and (ArgCount > 0) and (JsGetValueType(Args^) = JsString) then begin FirstArg := JsStringToUnicodeString(Args^); PPrev := PWideChar(FirstArg); P := FmtSpecPos(PPrev); end; if Assigned(P) then begin Inc(Arg); Inc(ArgIndex); while Assigned(P) do begin if ArgIndex > ArgCount - 1 then begin SetString(SCopy, PPrev, (P - PPrev) + 2); S := S + WideStringReplace(SCopy, '%%', '%', [rfReplaceAll]); end else begin SetString(SCopy, PPrev, P - PPrev); S := S + WideStringReplace(SCopy, '%%', '%', [rfReplaceAll]); case (P + 1)^ of 'd', 'i': S := S + UnicodeString(IntToStr(JsNumberToInt(Arg^))); 'f': S := S + UnicodeString(FloatToStr(JsNumberToDouble(Arg^), DefaultFormatSettings)); 'o': S := S + JsInspect(Arg^); 's': S := S + JsStringToUnicodeString(JsValueAsJsString(Arg^)); end; end; PPrev := P + 2; P := FmtSpecPos(PPrev); Inc(Arg); Inc(ArgIndex); end; S := S + WideStringReplace(PPrev, '%%', '%', [rfReplaceAll]); end else begin for I := 0 to ArgCount - 1 do begin if S <> '' then S := S + ' '; S := S + JsStringToUnicodeString(JsValueAsJsString(Arg^)); Inc(Arg); end; end; DoLog(S, Level); end; function TConsole.Log(const Args: array of JsValueRef; Level: TInfoLevel): JsValueRef; var P: PJsValueRef; L: Integer; begin P := nil; L := Length(Args); if L > 0 then P := @Args[0]; Result := Log(P, L, Level); end; class procedure TConsole.RegisterMethods(AInstance: JsValueRef); begin RegisterMethod(AInstance, 'assert', @TConsole.Assert); RegisterMethod(AInstance, 'log', @TConsole.LogNone); RegisterMethod(AInstance, 'info', @TConsole.LogInfo); RegisterMethod(AInstance, 'warn', @TConsole.LogWarn); RegisterMethod(AInstance, 'error', @TConsole.LogError); RegisterMethod(AInstance, 'exception', @TConsole.LogError); end; end. ================================================ FILE: samples/HostSample/scripts/json2.js ================================================ // json2.js // 2016-10-28 // Public Domain. // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. // See http://www.JSON.org/js.html // This code should be minified before deployment. // See http://javascript.crockford.com/jsmin.html // USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO // NOT CONTROL. // This file creates a global JSON object containing two methods: stringify // and parse. This file provides the ES5 JSON capability to ES3 systems. // If a project might run on IE8 or earlier, then this file should be included. // This file does nothing on ES5 systems. // JSON.stringify(value, replacer, space) // value any JavaScript value, usually an object or array. // replacer an optional parameter that determines how object // values are stringified for objects. It can be a // function or an array of strings. // space an optional parameter that specifies the indentation // of nested structures. If it is omitted, the text will // be packed without extra whitespace. If it is a number, // it will specify the number of spaces to indent at each // level. If it is a string (such as "\t" or " "), // it contains the characters used to indent at each level. // This method produces a JSON text from a JavaScript value. // When an object value is found, if the object contains a toJSON // method, its toJSON method will be called and the result will be // stringified. A toJSON method does not serialize: it returns the // value represented by the name/value pair that should be serialized, // or undefined if nothing should be serialized. The toJSON method // will be passed the key associated with the value, and this will be // bound to the value. // For example, this would serialize Dates as ISO strings. // Date.prototype.toJSON = function (key) { // function f(n) { // // Format integers to have at least two digits. // return (n < 10) // ? "0" + n // : n; // } // return this.getUTCFullYear() + "-" + // f(this.getUTCMonth() + 1) + "-" + // f(this.getUTCDate()) + "T" + // f(this.getUTCHours()) + ":" + // f(this.getUTCMinutes()) + ":" + // f(this.getUTCSeconds()) + "Z"; // }; // You can provide an optional replacer method. It will be passed the // key and value of each member, with this bound to the containing // object. The value that is returned from your method will be // serialized. If your method returns undefined, then the member will // be excluded from the serialization. // If the replacer parameter is an array of strings, then it will be // used to select the members to be serialized. It filters the results // such that only members with keys listed in the replacer array are // stringified. // Values that do not have JSON representations, such as undefined or // functions, will not be serialized. Such values in objects will be // dropped; in arrays they will be replaced with null. You can use // a replacer function to replace those with JSON values. // JSON.stringify(undefined) returns undefined. // The optional space parameter produces a stringification of the // value that is filled with line breaks and indentation to make it // easier to read. // If the space parameter is a non-empty string, then that string will // be used for indentation. If the space parameter is a number, then // the indentation will be that many spaces. // Example: // text = JSON.stringify(["e", {pluribus: "unum"}]); // // text is '["e",{"pluribus":"unum"}]' // text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t"); // // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' // text = JSON.stringify([new Date()], function (key, value) { // return this[key] instanceof Date // ? "Date(" + this[key] + ")" // : value; // }); // // text is '["Date(---current time---)"]' // JSON.parse(text, reviver) // This method parses a JSON text to produce an object or array. // It can throw a SyntaxError exception. // The optional reviver parameter is a function that can filter and // transform the results. It receives each of the keys and values, // and its return value is used instead of the original value. // If it returns what it received, then the structure is not modified. // If it returns undefined then the member is deleted. // Example: // // Parse the text. Values that look like ISO date strings will // // be converted to Date objects. // myData = JSON.parse(text, function (key, value) { // var a; // if (typeof value === "string") { // a = // /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); // if (a) { // return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], // +a[5], +a[6])); // } // } // return value; // }); // myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { // var d; // if (typeof value === "string" && // value.slice(0, 5) === "Date(" && // value.slice(-1) === ")") { // d = new Date(value.slice(5, -1)); // if (d) { // return d; // } // } // return value; // }); // This is a reference implementation. You are free to copy, modify, or // redistribute. /*jslint eval, for, this */ /*property JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length, parse, prototype, push, replace, slice, stringify, test, toJSON, toString, valueOf */ // Create a JSON object only if one does not already exist. We create the // methods in a closure to avoid creating global variables. if (typeof JSON !== "object") { JSON = {}; } (function () { "use strict"; var rx_one = /^[\],:{}\s]*$/; var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; var rx_four = /(?:^|:|,)(?:\s*\[)+/g; var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; function f(n) { // Format integers to have at least two digits. return n < 10 ? "0" + n : n; } function this_value() { return this.valueOf(); } if (typeof Date.prototype.toJSON !== "function") { Date.prototype.toJSON = function () { return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + f(this.getUTCMonth() + 1) + "-" + f(this.getUTCDate()) + "T" + f(this.getUTCHours()) + ":" + f(this.getUTCMinutes()) + ":" + f(this.getUTCSeconds()) + "Z" : null; }; Boolean.prototype.toJSON = this_value; Number.prototype.toJSON = this_value; String.prototype.toJSON = this_value; } var gap; var indent; var meta; var rep; function quote(string) { // If the string contains no control characters, no quote characters, and no // backslash characters, then we can safely slap some quotes around it. // Otherwise we must also replace the offending characters with safe escape // sequences. rx_escapable.lastIndex = 0; return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) { var c = meta[a]; return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }) + "\"" : "\"" + string + "\""; } function str(key, holder) { // Produce a string from holder[key]. var i; // The loop counter. var k; // The member key. var v; // The member value. var length; var mind = gap; var partial; var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value. if (value && typeof value === "object" && typeof value.toJSON === "function") { value = value.toJSON(key); } // If we were called with a replacer function, then call the replacer to // obtain a replacement value. if (typeof rep === "function") { value = rep.call(holder, key, value); } // What happens next depends on the value's type. switch (typeof value) { case "string": return quote(value); case "number": // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite(value) ? String(value) : "null"; case "boolean": case "null": // If the value is a boolean or null, convert it to a string. Note: // typeof null does not produce "null". The case is included here in // the remote chance that this gets fixed someday. return String(value); // If the type is "object", we might be dealing with an object or an array or // null. case "object": // Due to a specification blunder in ECMAScript, typeof null is "object", // so watch out for that case. if (!value) { return "null"; } // Make an array to hold the partial results of stringifying this object value. gap += indent; partial = []; // Is the value an array? if (Object.prototype.toString.apply(value) === "[object Array]") { // The value is an array. Stringify every element. Use null as a placeholder // for non-JSON values. length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || "null"; } // Join all of the elements together, separated with commas, and wrap them in // brackets. v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]"; gap = mind; return v; } // If the replacer is an array, use it to select the members to be stringified. if (rep && typeof rep === "object") { length = rep.length; for (i = 0; i < length; i += 1) { if (typeof rep[i] === "string") { k = rep[i]; v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } else { // Otherwise, iterate through all of the keys in the object. for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + ( gap ? ": " : ":" ) + v); } } } } // Join all of the member texts together, separated with commas, // and wrap them in braces. v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}"; gap = mind; return v; } } // If the JSON object does not yet have a stringify method, give it one. if (typeof JSON.stringify !== "function") { meta = { // table of character substitutions "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", "\"": "\\\"", "\\": "\\\\" }; JSON.stringify = function (value, replacer, space) { // The stringify method takes a value and an optional replacer, and an optional // space parameter, and returns a JSON text. The replacer can be a function // that can replace values, or an array of strings that will select the keys. // A default replacer method can be provided. Use of the space parameter can // produce text that is more easily readable. var i; gap = ""; indent = ""; // If the space parameter is a number, make an indent string containing that // many spaces. if (typeof space === "number") { for (i = 0; i < space; i += 1) { indent += " "; } // If the space parameter is a string, it will be used as the indent string. } else if (typeof space === "string") { indent = space; } // If there is a replacer, it must be a function or an array. // Otherwise, throw an error. rep = replacer; if (replacer && typeof replacer !== "function" && (typeof replacer !== "object" || typeof replacer.length !== "number")) { throw new Error("JSON.stringify"); } // Make a fake root object containing our value under the key of "". // Return the result of stringifying the value. return str("", {"": value}); }; } // If the JSON object does not yet have a parse method, give it one. if (typeof JSON.parse !== "function") { JSON.parse = function (text, reviver) { // The parse method takes a text and an optional reviver function, and returns // a JavaScript value if the text is a valid JSON text. var j; function walk(holder, key) { // The walk method is used to recursively walk the resulting structure so // that modifications can be made. var k; var v; var value = holder[key]; if (value && typeof value === "object") { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); } // Parsing happens in four stages. In the first stage, we replace certain // Unicode characters with escape sequences. JavaScript handles many characters // incorrectly, either silently deleting them, or treating them as line endings. text = String(text); rx_dangerous.lastIndex = 0; if (rx_dangerous.test(text)) { text = text.replace(rx_dangerous, function (a) { return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }); } // In the second stage, we run the text against regular expressions that look // for non-JSON patterns. We are especially concerned with "()" and "new" // because they can cause invocation, and "=" because it can cause mutation. // But just to be safe, we want to reject all unexpected forms. // We split the second stage into 4 regexp operations in order to work around // crippling inefficiencies in IE's and Safari's regexp engines. First we // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we // replace all simple value tokens with "]" characters. Third, we delete all // open brackets that follow a colon or comma or that begin the text. Finally, // we look to see that the remaining characters are only whitespace or "]" or // "," or ":" or "{" or "}". If that is so, then the text is safe for eval. if ( rx_one.test( text .replace(rx_two, "@") .replace(rx_three, "]") .replace(rx_four, "") ) ) { // In the third stage we use the eval function to compile the text into a // JavaScript structure. The "{" operator is subject to a syntactic ambiguity // in JavaScript: it can begin a block or an object literal. We wrap the text // in parens to eliminate the ambiguity. j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing // each name/value pair to a reviver function for possible transformation. return (typeof reviver === "function") ? walk({"": j}, "") : j; } // If the text is not JSON parseable, then a SyntaxError is thrown. throw new SyntaxError("JSON.parse"); }; } }()); ================================================ FILE: samples/HostSample/scripts/main.js ================================================ var p = new Promise((resolve, reject) => { setTimeout(c => { resolve("Success!"); }, 100, console); }); p.then( r => { console.info("Promise: %o", r); } ).catch( e => { console.error("Promise: %o", e); } ); testPromise(200).then( x => { console.info("testPromise: %o", x); }).catch( e => { console.error("testPromise: %o", e); } ); import('json2').then( m => { setTimeout(c => { c.log("(timeout 1000) Current time: ", new Date()) }, 1000, console); setTimeout(c => { c.log("(timeout 2000) Current time: ", new Date()) }, 2000, console); setTimeout(c => { c.log("(timeout 3000) Current time: ", new Date()); setInterval(c => { c.log("(interval 500) Current time: ", new Date()) }, 500, console); }, 3000, console); var f = function (console) { console.log("Current time: ", new Date()); console.info("%s: %s", "Info", "Info message"); console.warn("%s: %s", "Warning", "Warning message"); console.error("%s: %s %d", "Error", "Error message", 42); var o = {int_prop: 42, str_prop: "Hello", float_prop: 3.14, array_prop: [42, "Hello", 3.14]}; console.log(JSON.stringify(o)); console.log("%o", o); }; f(console); console.log(""); var console2 = new Console(); f(console2); } ).catch( e => { console.error("%o", e); } ); ================================================ FILE: samples/NodeSample/EventEmitter.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit EventEmitter; {$include common.inc} interface uses Classes, SysUtils, Types, Compat, ChakraCore, ChakraCommon, ChakraCoreUtils, ChakraCoreClasses; const DefaultMaxListeners = 10; type TEventEmitter = class; { TEvent } TEvent = class private FName: JsValueRef; FListeners: TList; FOnceList: TList; FOwner: TEventEmitter; function GetListenerCount: Integer; function GetListeners(Index: Integer): JsValueRef; public constructor Create(AOwner: TEventEmitter; AName: JsValueRef); destructor Destroy; override; function AddListener(AListener: JsValueRef; AOnce: Boolean = False): Integer; procedure Emit(Args: PJsValueRef; ArgCount: Word); overload; procedure Emit(const Args: array of JsValueRef); overload; procedure PrependListener(AListener: JsValueRef; AOnce: Boolean = False); function RemoveListener(AListener: JsValueRef): Integer; procedure RemoveListeners; property Name: JsValueRef read FName; property ListenerCount: Integer read GetListenerCount; property Listeners[Index: Integer]: JsValueRef read GetListeners; property Owner: TEventEmitter read FOwner; end; { TEventEmitter } TEventEmitter = class(TNativeObject) private FEvents: TList; FMaxListeners: Integer; function GetEventCount: Integer; function GetEvents(Index: Integer): TEvent; function GetMaxListeners: Integer; procedure SetMaxListeners(AValue: Integer); protected class function InitializePrototype(AConstructor: JsValueRef): JsValueRef; override; class procedure RegisterMethods(AInstance: JsValueRef); override; function _AddListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _Emit(Args: PJsValueRef; ArgCount: Word): JsValueRef; function _EventNames(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _GetMaxListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _ListenerCount(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _Listeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _Off(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _On(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _Once(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _PrependListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _PrependOnceListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _RemoveAllListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _RemoveListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _SetMaxListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; function _RawListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; public constructor Create(Args: PJsValueRef = nil; ArgCount: Word = 0; AFinalize: Boolean = False); overload; override; destructor Destroy; override; procedure AddListener(Name, Listener: JsValueRef; Once: Boolean = False); function FindEvent(Name: JsValueRef): TEvent; procedure PrependListener(Name, Listener: JsValueRef; Once: Boolean = False); procedure RemoveListener(Name, Listener: JsValueRef); property EventCount: Integer read GetEventCount; property Events[Index: Integer]: TEvent read GetEvents; property MaxListeners: Integer read GetMaxListeners write SetMaxListeners; end; implementation // TODO move to ChakraCoreUtils type JsValueTypes = set of JsValueType; const JsValueTypeStrings: array[JsValueType] of UnicodeString = ( 'undefined', 'null', 'number', 'string', 'boolean', 'object', 'function', 'error', 'array', 'symbol', 'ArrayBuffer', 'TypedArray', 'DataView' ); function JsValueTypesStr(ValueTypes: JsValueTypes): UnicodeString; var ValueType: JsValueType; begin Result := ''; for ValueType := Low(JsValueType) to High(JsValueType) do if ValueType in ValueTypes then begin if Result <> '' then Result := Result + ', '; Result := Result + JsValueTypeStrings[ValueType]; end; end; procedure CheckArgCount(Expected, Actual: Word); begin if Expected <> Actual then raise Exception.CreateFmt('Invalid number of arguments: %d (expected %d)', [Actual, Expected]); end; procedure CheckMinArgCount(Expected, Actual: Word); begin if Expected > Actual then raise Exception.CreateFmt('Invalid number of arguments: %d (expected at least %d)', [Actual, Expected]); end; procedure CheckArgValueType(Expected: JsValueType; Arg: JsValueRef); overload; var ArgValueType: JsValueType; begin ArgValueType := JsGetValueType(Arg); if Expected <> ArgValueType then raise Exception.CreateFmt('Invalid argument type %s (expected %s)', [JsValueTypeStrings[ArgValueType], JsValueTypeStrings[Expected]]); end; procedure CheckArgValueType(Expected: JsValueTypes; Arg: JsValueRef); overload; var ArgValueType: JsValueType; begin ArgValueType := JsGetValueType(Arg); if not (ArgValueType in Expected) then raise Exception.CreateFmt('Invalid argument type %s (expected %s)', [JsValueTypesStr(Expected)]); end; { TEvent private } function TEvent.GetListenerCount: Integer; begin Result := FListeners.Count; end; function TEvent.GetListeners(Index: Integer): JsValueRef; begin Result := FListeners[Index]; end; { TEvent public } constructor TEvent.Create(AOwner: TEventEmitter; AName: JsValueRef); begin inherited Create; FOwner := AOwner; FName := AName; FListeners := TList.Create; FOnceList := TList.Create; if Assigned(FOwner) then FOwner.FEvents.Add(Self); end; destructor TEvent.Destroy; begin if Assigned(FOwner) then FOwner.FEvents.Remove(Self); FListeners.Free; FOnceList.Free; inherited Destroy; end; function TEvent.AddListener(AListener: JsValueRef; AOnce: Boolean): Integer; begin Result := FListeners.Add(AListener); if AOnce and (FOnceList.IndexOf(AListener) = -1) then FOnceList.Add(AListener); end; procedure TEvent.Emit(Args: PJsValueRef; ArgCount: Word); var NewArgs: array of JsValueRef; I, J: Integer; begin SetLength(NewArgs, ArgCount + 1); NewArgs[0] := FOwner.Instance; if ArgCount > 0 then Move(Args^, NewArgs[1], ArgCount * SizeOf(JsValueRef)); for I := 0 to FListeners.Count - 1 do JsCallFunction(FListeners[I], @NewArgs[0], ArgCount + 1); for I := FListeners.Count - 1 downto 0 do begin J := FOnceList.IndexOf(FListeners[I]); if J <> -1 then begin FListeners.Delete(I); FOnceList.Delete(J); end; end; end; procedure TEvent.Emit(const Args: array of JsValueRef); var PArg: PJsValueRef; Len: Integer; begin PArg := nil; Len := Length(Args); if Len > 0 then PArg := @Args[0]; Emit(PArg, Len); end; procedure TEvent.PrependListener(AListener: JsValueRef; AOnce: Boolean); begin FListeners.Insert(0, AListener); if AOnce and (FOnceList.IndexOf(AListener) = -1) then FOnceList.Add(AListener); end; function TEvent.RemoveListener(AListener: JsValueRef): Integer; begin Result := FListeners.Remove(AListener); end; procedure TEvent.RemoveListeners; begin FListeners.Clear; end; { TEventEmitter private } function TEventEmitter.GetEventCount: Integer; begin Result := FEvents.Count; end; function TEventEmitter.GetEvents(Index: Integer): TEvent; begin Result := TEvent(FEvents[Index]); end; function TEventEmitter.GetMaxListeners: Integer; begin Result := FMaxListeners; if Result = -1 then Result := JsNumberToInt(JsValueAsJsNumber(JsGetProperty(Instance, 'defaultMaxListeners'))); end; procedure TEventEmitter.SetMaxListeners(AValue: Integer); begin if AValue <> FMaxListeners then begin if AValue < 0 then FMaxListeners := -1 else FMaxListeners := AValue; end; end; { TEventEmitter protected } class function TEventEmitter.InitializePrototype(AConstructor: JsValueRef): JsValueRef; begin Result := inherited InitializePrototype(AConstructor); JsSetProperty(Result, 'defaultMaxListeners', IntToJsNumber(DefaultMaxListeners)); RegisterClassMethod(AConstructor, 'listenerCount', @TEventEmitter._ListenerCount); end; class procedure TEventEmitter.RegisterMethods(AInstance: JsValueRef); begin RegisterMethod(AInstance, 'addListener', @TEventEmitter._AddListener); RegisterMethod(AInstance, 'emit', @TEventEmitter._Emit); RegisterMethod(AInstance, 'eventNames', @TEventEmitter._EventNames); RegisterMethod(AInstance, 'getMaxListeners', @TEventEmitter._GetMaxListeners); RegisterMethod(AInstance, 'listeners', @TEventEmitter._Listeners); RegisterMethod(AInstance, 'off', @TEventEmitter._Off); RegisterMethod(AInstance, 'on', @TEventEmitter._On); RegisterMethod(AInstance, 'once', @TEventEmitter._Once); RegisterMethod(AInstance, 'prependListener', @TEventEmitter._PrependListener); RegisterMethod(AInstance, 'prependOnceListener', @TEventEmitter._PrependOnceListener); RegisterMethod(AInstance, 'removeAllListeners', @TEventEmitter._RemoveAllListeners); RegisterMethod(AInstance, 'removeListener', @TEventEmitter._RemoveListener); RegisterMethod(AInstance, 'setMaxListeners', @TEventEmitter._SetMaxListeners); RegisterMethod(AInstance, 'rawListeners', @TEventEmitter._RawListeners); end; function TEventEmitter._AddListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := _On(Args, ArgCount); end; function TEventEmitter._Emit(Args: PJsValueRef; ArgCount: Word): JsValueRef; var Event: TEvent; begin Result := JsUndefinedValue; try CheckMinArgCount(1, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^); Event := FindEvent(Args^); if not Assigned(Event) then raise EListError.CreateFmt('Event %s not found', [JsStringToUnicodeString(JsValueAsJsString(Args^))]); Inc(Args); Dec(ArgCount); Event.Emit(Args, ArgCount); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._EventNames(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; var I: Integer; begin Result := JsUndefinedValue; try Result := JsCreateArray(EventCount); for I := 0 to EventCount - 1 do JsSetIndexedProperty(Result, IntToJsNumber(I), Events[I].Name); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._GetMaxListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try Result := IntToJsNumber(GetMaxListeners); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._ListenerCount(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; var Emitter: TEventEmitter; Event: TEvent; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsObject], Args^[0]); CheckArgValueType([JsSymbol, JsString], Args^[1]); Emitter := TEventEmitter(JsGetExternalData(Args^[0])); Event := Emitter.FindEvent(Args^[1]); if not Assigned(Event) then raise EListError.CreateFmt('Event ''%s'' not found for %s', [JsStringToUnicodeString(JsValueAsJsString(Args^[1])), Emitter.ClassName]); Result := IntToJsNumber(Event.ListenerCount); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._Listeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; var Event: TEvent; I: Integer; begin Result := JsUndefinedValue; try CheckArgCount(1, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); Event := FindEvent(Args^[0]); if not Assigned(Event) then raise EListError.CreateFmt('Event %s not found', [JsStringToUnicodeString(JsValueAsJsString(Args^[0]))]); Result := JsCreateArray(Event.ListenerCount); for I := 0 to Event.ListenerCount - 1 do JsSetIndexedProperty(Result, IntToJsNumber(I), Event.Listeners[I]); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._Off(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); CheckArgValueType(JsFunction, Args^[1]); RemoveListener(Args^[0], Args^[1]); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._On(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); CheckArgValueType(JsFunction, Args^[1]); AddListener(Args^[0], Args^[1]); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._Once(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); CheckArgValueType(JsFunction, Args^[1]); AddListener(Args^[0], Args^[1], True); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._PrependListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); CheckArgValueType(JsFunction, Args^[1]); PrependListener(Args^[0], Args^[1]); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._PrependOnceListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(2, ArgCount); CheckArgValueType([JsSymbol, JsString], Args^[0]); CheckArgValueType(JsFunction, Args^[1]); PrependListener(Args^[0], Args^[1], True); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._RemoveAllListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; var I: Integer; Event: TEvent; begin Result := JsUndefinedValue; try if ArgCount = 0 then begin for I := 0 to EventCount - 1 do Events[I].RemoveListeners; end else begin CheckArgValueType([JsSymbol, JsString], Args^[0]); Event := FindEvent(Args^[0]); if not Assigned(Event) then raise EListError.CreateFmt('Event %s not found', [JsStringToUnicodeString(JsValueAsJsString(Args^[0]))]); Event.RemoveListeners; end; Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._RemoveListener(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := _Off(Args, ArgCount); end; function TEventEmitter._SetMaxListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try CheckArgCount(1, ArgCount); CheckArgValueType(JsNumber, Args^[0]); MaxListeners := JsNumberToInt(Args^[0]); Result := Instance; except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TEventEmitter._RawListeners(Args: PJsValueRefArray; ArgCount: Word): JsValueRef; begin Result := _Listeners(Args, ArgCount); end; { TEventEmitter public } constructor TEventEmitter.Create(Args: PJsValueRef; ArgCount: Word; AFinalize: Boolean); begin inherited Create(Args, ArgCount, AFinalize); FEvents := TList.Create; FMaxListeners := -1; TEvent.Create(Self, StringToJsString('newListener')); TEvent.Create(Self, StringToJsString('removeListener')); end; destructor TEventEmitter.Destroy; var I: Integer; begin for I := FEvents.Count - 1 downto 0 do TEvent(FEvents[I]).Free; FEvents.Free; inherited Destroy; end; procedure TEventEmitter.AddListener(Name, Listener: JsValueRef; Once: Boolean); var Event: TEvent; begin Event := FindEvent(Name); if not Assigned(Event) then Event := TEvent.Create(Self, Name); Event.AddListener(Listener, Once); Event := FindEvent(StringToJsString('newListener')); Event.Emit([Name, Listener]); end; function TEventEmitter.FindEvent(Name: JsValueRef): TEvent; var I: Integer; begin Result := nil; for I := 0 to EventCount - 1 do if JsEqual(Name, Events[I].Name) then begin Result := Events[I]; Break; end; end; procedure TEventEmitter.PrependListener(Name, Listener: JsValueRef; Once: Boolean); var Event: TEvent; begin Event := FindEvent(Name); if not Assigned(Event) then Event := TEvent.Create(Self, Name); Event.PrependListener(Listener, Once); Event := FindEvent(StringToJsString('newListener')); Event.Emit([Name, Listener]); end; procedure TEventEmitter.RemoveListener(Name, Listener: JsValueRef); var Event: TEvent; begin Event := FindEvent(Name); if Assigned(Event) then Event.RemoveListener(Listener); Event := FindEvent(StringToJsString('removeListener')); Event.Emit([Name, Listener]); end; end. ================================================ FILE: samples/NodeSample/NodeMainData.dfm ================================================ object DataModuleMain: TDataModuleMain OldCreateOrder = False OnCreate = DataModuleCreate OnDestroy = DataModuleDestroy Height = 265 Width = 368 end ================================================ FILE: samples/NodeSample/NodeMainData.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit NodeMainData; interface {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cwstring, {$endif}{$endif} {$ifdef WINDOWS} Windows, {$endif} SysUtils, Classes, Types, Contnrs, {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Compat, ChakraCommon, ChakraCore, ChakraCoreUtils, ChakraCoreClasses, Console, NodeProcess; type TNodeModule = class private FFileName: UnicodeString; FHandle: JsvalueRef; FParent: TNodeModule; FRequire: JsValueRef; public constructor Create(AParent: TNodeModule); property FileName: UnicodeString read FFileName; property Handle: JsValueRef read FHandle; property Parent: TNodeModule read FParent; property Require: JsValueRef read FRequire; end; { TDataModuleMain } TDataModuleMain = class(TDataModule) procedure DataModuleCreate(Sender: TObject); procedure DataModuleDestroy(Sender: TObject); private FBaseDir: UnicodeString; FConsole: TConsole; FContext: TChakraCoreContext; FMainModule: TNodeModule; FModules: TObjectList; FNodeBaseDir: UnicodeString; FProcess: TProcess; FRuntime: TChakraCoreRuntime; FUseAnsiColors: Boolean; procedure ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel = ilNone); procedure ContextActivate(Sender: TObject); procedure ContextLoadModule(Sender: TObject; Module: TChakraModule); procedure ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); function FindModule(ARequire: JsValueRef): TNodeModule; overload; function FindModule(const AFileName: UnicodeString): TNodeModule; overload; procedure LoadModule(Module: TNodeModule; const FileName: UnicodeString); function LoadPackage(const FileName: UnicodeString): JsValueRef; function Require(CallerModule: TNodeModule; const Path: UnicodeString): JsValueRef; function Resolve(const Request, CurrentPath: UnicodeString): UnicodeString; function ResolveDirectory(const Request: UnicodeString; out FileName: UnicodeString): Boolean; function ResolveFile(const Request: UnicodeString; out FileName: UnicodeString): Boolean; function ResolveIndex(const Request: UnicodeString; out FileName: UnicodeString): Boolean; function ResolveModules(const Request: UnicodeString; out FileName: UnicodeString): Boolean; function RunModule(Module: TNodeModule): JsValueRef; public procedure Execute(const FileName: UnicodeString); property BaseDir: UnicodeString read FBaseDir; property Console: TConsole read FConsole; property Context: TChakraCoreContext read FContext; property NodeBaseDir: UnicodeString read FNodeBaseDir; property Runtime: TChakraCoreRuntime read FRuntime; property UseAnsiColors: Boolean read FUseAnsiColors write FUseAnsiColors; end; implementation {$R *.dfm} function JsInspectHandler(Value: JsValueRef; E: Exception): UnicodeString; begin Result := WideFormat('[%s] %s', [E.ClassName, E.Message]); end; function CombinePath(const Path, Name: UnicodeString): UnicodeString; begin Result := IncludeTrailingPathDelimiter(Path) + Name; end; function ParentPath(const Path: UnicodeString): UnicodeString; begin Result := ExtractFilePath(ExcludeTrailingPathDelimiter(Path)); end; function LoadFile(const FileName: UnicodeString): UnicodeString; var FileStream: TFileStream; S: UTF8String; begin Result := ''; FileStream := TFileStream.Create(FileName, fmOpenRead); try if FileStream.Size = 0 then Exit; SetLength(S, FileStream.Size); FileStream.Read(S[1], FileStream.Size); Result := UTF8ToString(S); finally FileStream.Free; end; end; function PostTimedTask(Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer; RepeatCount: Integer): JsValueRef; var DataModule: TDataModuleMain absolute CallbackState; AMessage: TTaskMessage; Delay: Cardinal; FuncArgs: array of JsValueRef; I: Integer; begin Result := JsUndefinedValue; if ArgCount < 2 then // thisarg, function to call, optional: delay, function args raise Exception.Create('Invalid arguments'); if ArgCount >= 3 then Delay := JsNumberToInt(Args^[2]) else Delay := 0; if ArgCount >= 4 then begin SetLength(FuncArgs, ArgCount - 3); for I := 0 to ArgCount - 4 do FuncArgs[I] := Args^[I + 3]; end; AMessage := TTaskMessage.Create(DataModule.Context, Args^[1], Args^[0], FuncArgs, Delay, RepeatCount); try DataModule.Context.PostMessage(AMessage); except AMessage.Free; raise; end; end; function Require_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var DataModule: TDataModuleMain absolute CallbackState; CallerModule: TNodeModule; Path: UnicodeString; begin Result := JsUndefinedValue; try if ArgCount <> 2 then raise Exception.Create('require: module name not specified'); if JsGetValueType(Args^[1]) <> JsString then raise Exception.Create('require: module name not a string value'); CallerModule := DataModule.FindModule(Callee); Path := JsStringToUnicodeString(Args^[1]); if PathDelim <> '/' then Path := UnicodeStringReplace(Path, '/', PathDelim, [rfReplaceAll]); Result := DataModule.Require(CallerModule, Path); except on E: EChakraCoreScript do JsThrowError(WideFormat('%s (%d, %d): [%s] %s', [E.ScriptURL, E.Line + 1, E.Column + 1, E.ClassName, E.Message])); on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function SetInterval_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := PostTimedTask(Args, ArgCount, CallbackState, -1); // repeat endlessly end; function SetTimeout_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := PostTimedTask(Args, ArgCount, CallbackState, 1); // run once end; type THackPromiseMessage = class(TPromiseMessage); TDummyPromiseThread = class(TThread) private FMessage: TPromiseMessage; FTimeout: Cardinal; FValue: JsValueRef; protected procedure Execute; override; public constructor Create(AMessage: TPromiseMessage; ATimeout: Cardinal); end; { TTestPromiseThread } procedure TDummyPromiseThread.Execute; begin Sleep(FTimeout); THackPromiseMessage(FMessage).SetStatus(psResolved, FValue); end; constructor TDummyPromiseThread.Create(AMessage: TPromiseMessage; ATimeout: Cardinal); begin FMessage := AMessage; FTimeout := ATimeout; FValue := StringToJsString('Success!'); JsAddRef(FValue); FreeOnTerminate := True; inherited Create(False); end; procedure TDataModuleMain.ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel); const StartBlocks: array[TInfoLevel] of RawByteString = ('', #$1b'[32;1m', #$1b'[33;1m', #$1b'[31;1m'); EndBlocks: array[Boolean] of RawByteString = ('', #$1b'[0m'); {$ifdef WINDOwS} BackgroundMask = $F0; TextColors: array[TInfoLevel] of Word = (0, FOREGROUND_GREEN or FOREGROUND_INTENSITY, FOREGROUND_GREEN or FOREGROUND_RED or FOREGROUND_INTENSITY, FOREGROUND_RED or FOREGROUND_INTENSITY); {$endif} var {$ifdef WINDOWS} Info: TConsoleScreenBufferInfo; {$endif} S: UTF8String; begin S := UTF8Encode(Text); {$ifdef WINDOWS} if UseAnsiColors then Writeln(StartBlocks[Level], S, EndBlocks[Level <> ilNone]) else begin if (Level = ilNone) or not GetConsoleScreenBufferInfo(TTextRec(Output).Handle, Info) then begin Writeln(S); Exit; end; SetConsoleTextAttribute(TTextRec(Output).Handle, Info.wAttributes and BackgroundMask or TextColors[Level]); try Writeln(S); finally SetConsoleTextAttribute(TTextRec(Output).Handle, Info.wAttributes); end; end; {$else} Writeln(StartBlocks[Level], S, EndBlocks[Level <> ilNone]); {$endif} end; procedure TDataModuleMain.ContextActivate(Sender: TObject); begin // expose global.console FConsole := TConsole.Create; FConsole.OnLog := ConsoleLog; JsSetProperty(FContext.Global, 'console', FConsole.Instance); // expose additional functions JsSetCallback(FContext.Global, 'setTimeout', @SetTimeout_Callback, Self); JsSetCallback(FContext.Global, 'setInterval', @SetInterval_Callback, Self); FProcess := TProcess.Create; JsSetProperty(FContext.Global, 'process', FProcess.Instance); JsSetCallback(FContext.Global, 'require', @Require_Callback, Self); end; procedure TDataModuleMain.ContextLoadModule(Sender: TObject; Module: TChakraModule); begin // TODO ES6 modules end; procedure TDataModuleMain.ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); begin if NativeObject is TConsole then TConsole(NativeObject).OnLog := ConsoleLog; end; function TDataModuleMain.FindModule(ARequire: JsValueRef): TNodeModule; var I: Integer; begin Result := nil; for I := 0 to FModules.Count - 1 do if TNodeModule(FModules[I]).Require = ARequire then begin Result := TNodeModule(FModules[I]); Break; end; end; function TDataModuleMain.FindModule(const AFileName: UnicodeString): TNodeModule; var I: Integer; begin Result := nil; for I := 0 to FModules.Count - 1 do if WideSameText(AFileName, TNodeModule(FModules[I]).FileName) then begin Result := TNodeModule(FModules[I]); Break; end; end; procedure TDataModuleMain.LoadModule(Module: TNodeModule; const FileName: UnicodeString); var WrapScript: UnicodeString; begin if ExtractFileExt(FileName) = '.json' then WrapScript := '(function (exports, require, module, __filename, __dirname) {' + sLineBreak + 'module.exports = ' + LoadFile(FileName) + ';' + sLineBreak + '})' else WrapScript := '(function (exports, require, module, __filename, __dirname) {' + sLineBreak + LoadFile(FileName) + sLineBreak + '})'; Module.FFileName := FileName; Module.FHandle := FContext.RunScript(WrapScript, FileName); JsSetProperty(Module.Handle, 'exports', JsCreateObject); JsSetProperty(Module.Handle, '__dirname', StringToJsString(ExtractFilePath(FileName))); JsSetProperty(Module.Handle, '__filename', StringToJsString(FileName)); Module.FRequire := JsSetCallback(Module.Handle, 'require', @Require_Callback, Self); ConsoleLog(FConsole, WideFormat('Loaded module ''%s''', [ExtractRelativePath(FBaseDir, Module.FileName)]), ilInfo); end; function TDataModuleMain.LoadPackage(const FileName: UnicodeString): JsValueRef; begin Result := FContext.CallFunction('parse', [StringToJsString(LoadFile(FileName))], JsGetProperty(JsGlobal, 'JSON')); end; function TDataModuleMain.Require(CallerModule: TNodeModule; const Path: UnicodeString): JsValueRef; var FileName: UnicodeString; Module: TNodeModule; begin if Assigned(CallerModule) then FileName := Resolve(Path, ExtractFilePath(CallerModule.FileName)) else FileName := Resolve(Path, FBaseDir); if FileName = '' then raise Exception.CreateFmt('Module ''%s'' not found', [Path]); FileName := ExpandFileName(FileName); Module := FindModule(FileName); if not Assigned(Module) then begin Module := TNodeModule.Create(CallerModule); try FModules.Add(Module); LoadModule(Module, FileName); RunModule(Module); except on E: Exception do begin if Module <> FMainModule then FModules.Remove(Module); raise; end; end; end; Result := JsGetProperty(Module.Handle, 'exports'); end; function TDataModuleMain.Resolve(const Request, CurrentPath: UnicodeString): UnicodeString; var BasePaths: array[0..1] of UnicodeString; SRequest: UnicodeString; I: Integer; begin Result := ''; if Request = '' then Exit; if Request[1] = '/' then BasePaths[0] := {$ifdef MSWINDOWS}ExtractFileDrive(CurrentPath){$else}''{$endif}; if (Request[1] = PathDelim) or ((Length(Request) > 1) and (Request[1] = '.') and (Request[2] = PathDelim)) or ((Length(Request) > 2) and (Request[1] = '.') and (Request[2] = '.') and (Request[3] = PathDelim)) then BasePaths[0] := CurrentPath; BasePaths[1] := ExtractFilePath(ParamStr(0)) + '..' + PathDelim + '..' + PathDelim + '..' + PathDelim + 'ext' + PathDelim + 'node' + PathDelim + 'lib'; SRequest := Request; if PathDelim <> '/' then SRequest := UnicodeStringReplace(SRequest, '/', PathDelim, [rfReplaceAll]); for I := Low(BasePaths) to High(BasePaths) do begin if ResolveFile(IncludeTrailingPathDelimiter(BasePaths[I]) + SRequest, Result) then Exit; if ResolveDirectory(IncludeTrailingPathDelimiter(BasePaths[I]) + SRequest, Result) then Exit; end; if not ResolveModules(Request, Result) then Result := ''; end; function TDataModuleMain.ResolveDirectory(const Request: UnicodeString; out FileName: UnicodeString): Boolean; var Package, Main: UnicodeString; begin FileName := ''; Package := IncludeTrailingPathDelimiter(Request) + 'package.json'; if FileExists(Package) then begin Main := IncludeTrailingPathDelimiter(Request) + JsStringToUnicodeString(JsGetProperty(LoadPackage(Package), 'main')); if PathDelim <> '/' then Main := UnicodeStringReplace(Main, '/', PathDelim, [rfReplaceAll]); Result := ResolveFile(Main, FileName) or ResolveIndex(Main, FileName); if Result then Exit; end; Result := ResolveIndex(Request, FileName); end; function TDataModuleMain.ResolveFile(const Request: UnicodeString; out FileName: UnicodeString): Boolean; begin Result := False; FileName := ''; if FileExists(Request) and not DirectoryExists(Request) then begin FileName := Request; Result := True; end else if FileExists(Request + '.js') then begin FileName := Request + '.js'; Result := True; end else if FileExists(Request + '.json') then begin FileName := Request + '.json'; Result := True; end else if FileExists(Request + '.node') then begin FileName := Request + '.node'; Result := True; end; end; function TDataModuleMain.ResolveIndex(const Request: UnicodeString; out FileName: UnicodeString): Boolean; begin Result := False; FileName := ''; if FileExists(IncludeTrailingPathDelimiter(Request) + 'index.js') then begin FileName := IncludeTrailingPathDelimiter(Request) + 'index.js'; Result := True; end else if FileExists(IncludeTrailingPathDelimiter(Request) + 'index.json') then begin FileName := IncludeTrailingPathDelimiter(Request) + 'index.json'; Result := True; end else if FileExists(IncludeTrailingPathDelimiter(Request) + 'index.node') then begin FileName := IncludeTrailingPathDelimiter(Request) + 'index.node'; Result := True; end end; function TDataModuleMain.ResolveModules(const Request: UnicodeString; out FileName: UnicodeString): Boolean; var NodeModulePaths: array of UnicodeString; I: Integer; begin Result := False; FileName := ''; // TODO global paths etc. SetLength(NodeModulePaths, 1); NodeModulePaths[0] := IncludeTrailingPathDelimiter(FBaseDir) + 'node_modules'; for I := 0 to High(NodeModulePaths) do begin Result := ResolveFile(IncludeTrailingPathDelimiter(NodeModulePaths[I]) + Request, FileName); if Result then Break; Result := ResolveDirectory(IncludeTrailingPathDelimiter(NodeModulePaths[I]) + Request, FileName); if Result then Break; end; end; function TDataModuleMain.RunModule(Module: TNodeModule): JsValueRef; begin FContext.CallFunction(Module.Handle, [JsGetProperty(Module.Handle, 'exports'), Module.Require, Module.Handle, StringToJsString(Module.FileName), StringToJsString(ExtractFilePath(Module.FileName))], Module.Handle); Result := JsGetProperty(Module.Handle, 'exports'); end; procedure TDataModuleMain.DataModuleCreate(Sender: TObject); begin try JsInspectExceptionHandler := JsInspectHandler; FRuntime := TChakraCoreRuntime.Create([ccroEnableExperimentalFeatures, ccroDispatchSetExceptionsToDebugger]); FContext := TChakraCoreContext.Create(FRuntime); FContext.OnActivate := ContextActivate; FContext.OnLoadModule := ContextLoadModule; FContext.OnNativeObjectCreated := ContextNativeObjectCreated; FBaseDir := GetCurrentDir; FModules := TObjectList.Create; except FreeAndNil(FConsole); FreeAndNil(FContext); FreeAndNil(FRuntime); raise; end; end; procedure TDataModuleMain.DataModuleDestroy(Sender: TObject); begin FreeAndNil(FConsole); FreeAndNil(FProcess); FreeAndNil(FModules); FreeAndNil(FContext); FreeAndNil(FRuntime); end; procedure TDataModuleMain.Execute(const FileName: UnicodeString); var FullFileName: UnicodeString; begin FullFileName := ExpandFileName(FileName); FBaseDir := ExtractFilePath(FullFileName); FMainModule := TNodeModule.Create(nil); try FModules.Add(FMainModule); LoadModule(FMainModule, FullFileName); RunModule(FMainModule); except FModules.Remove(FMainModule); FMainModule := nil; raise; end; end; { TNodeModule public } constructor TNodeModule.Create(AParent: TNodeModule); begin inherited Create; FParent := AParent; end; end. ================================================ FILE: samples/NodeSample/NodeProcess.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit NodeProcess; interface uses Classes, SysUtils, Compat, ChakraCommon, ChakraCoreUtils, ChakraCoreClasses, EventEmitter; type { TProcess } TProcess = class(TEventEmitter) protected class procedure RegisterMethods(AInstance: JsValueRef); override; class procedure RegisterProperties(AInstance: JsValueRef); override; function _Binding(Args: PJsValueRef; ArgCount: Word): JsValueRef; function _Cwd(Args: PJsValueRef; ArgCount: Word): JsValueRef; public function Binding(const ModuleName: UnicodeString): JsValueRef; end; implementation function _ArgV: JsValueRef; var I: Integer; begin Result := JsCreateArray(ParamCount); for I := 0 to ParamCount do JsSetIndexedProperty(Result, IntToJsNumber(I), StringToJsString(UnicodeString(ParamStr(I)))); end; function _Env: JsValueRef; {$ifdef FPC} var I: Integer; S: array of AnsiString; {$endif FPC} begin Result := JsCreateObject; // TODO: implement for Delphi {$ifdef FPC} for I := 0 to GetEnvironmentVariableCount - 1 do begin S := GetEnvironmentString(I).Split(['=']); if (Length(S) > 1) and (not S[0].IsEmpty) then JsSetProperty(Result, S[0], StringToJsString(S[1])); end; {$endif FPC} end; { TProcess protected } class procedure TProcess.RegisterMethods(AInstance: JsValueRef); begin RegisterMethod(AInstance, 'binding', @TProcess._Binding); RegisterMethod(AInstance, 'cwd', @TProcess._Cwd); end; class procedure TProcess.RegisterProperties(AInstance: JsValueRef); const {$ifdef CPU64} sArch = 'x64'; {$else} sArch = 'x32'; {$endif} {$ifdef MSWINDOWS} sPlatform = 'win32'; {$endif} {$ifdef DARWIN} sPlatform = 'darwin'; {$endif} {$ifdef LINUX} sPlatform = 'linux'; {$endif} begin RegisterNamedProperty(AInstance, 'arch', False, True, False, StringToJsString(sArch)); RegisterNamedProperty(AInstance, 'argv', False, True, False, _ArgV); RegisterNamedProperty(AInstance, 'execPath', False, True, False, StringToJsString(ParamStr(0))); RegisterNamedProperty(AInstance, 'env', False, True, False, _Env); RegisterNamedProperty(AInstance, 'pid', False, True, False, IntToJsNumber(0{GetProcessID})); RegisterNamedProperty(AInstance, 'platform', False, True, False, StringToJsString(sPlatform)); end; function TProcess._Binding(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try if not Assigned(Args) or (ArgCount <> 1) then raise Exception.Create('Invalid arguments'); if (JsGetValueType(Args^) <> JsString) then raise Exception.Create('Invalid arguments'); Result := Binding(JsStringToUnicodeString(Args^)); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TProcess._Cwd(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := JsUndefinedValue; try Result := StringToJsString(GetCurrentDir); except on E: Exception do JsThrowError(UnicodeFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function TProcess.Binding(const ModuleName: UnicodeString): JsValueRef; begin Result := JsUndefinedValue; // TODO: node.js native bindings: buffer, uv, ... end; end. ================================================ FILE: samples/NodeSample/NodeSample.XE.dproj ================================================  {36d30f07-2980-4d75-905b-ab8c50757d35} NodeSample.dpr Debug DCC32 12.3 True Win32 Application VCL true true Base true true Base true ..\..\bin\$(Platform)\$(Config)\ChakraCoreHostSample.exe ..\..\bin\$(Platform)\$(Config) ..\..\lib\$(Platform)\$(Config) 00400000 vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) x86 ..\..\src;..\HostSample;$(DCC_UnitSearchPath) false true false 1 false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource
DataModuleMain
TDataModule
FormMain
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication NodeSample.dpr ..\..\..\samples\NodeSample\scripts\main.js ..\..\..\samples\NodeSample\scripts\main.wasm True False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 NodeSample © 2021 Ondrej Kelle NodeSample chakracore-delphi 1.0.0.0 True 12
================================================ FILE: samples/NodeSample/NodeSample.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\..\bin\Win32\Debug UnitOutputDir=..\..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\..\src;..\..\samples\HostSample Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=NodeSample LegalCopyright=© 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=NodeSample.exe ProductName=chakracore-delphi ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src;..\..\samples\HostSample [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: samples/NodeSample/NodeSample.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program NodeSample; {$APPTYPE CONSOLE} {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cthreads, {$endif}{$endif} SysUtils, Compat, ChakraCoreVersion, ChakraCoreUtils, NodeMainData in 'NodeMainData.pas' {DataModuleMain: TDataModule}; {$R *.res} procedure ShowInfo; begin Writeln(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); Writeln(Format('Built with %s', [GetBuildInfoString])); Writeln(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); Writeln; end; procedure Main; var DataModule: TDataModuleMain; begin ShowInfo; if ParamCount <> 1 then raise Exception.CreateFmt('Usage: %s ', [ExtractFileName(ParamStr(0))]); DataModule := TDataModuleMain.Create(nil); try DataModule.Execute(UnicodeString(ParamStr(1))); finally DataModule.Free; end; end; begin {$ifdef DELPHI2006_UP} ReportMemoryLeaksOnShutdown := True; {$endif} try Main; except on E: EChakraCoreScript do begin ExitCode := 1; Writeln(Format('%s (%d, %d): [%s] ''%s''' + sLineBreak + '%s', [E.ScriptURL, E.Line + 1, E.Column + 1, E.ClassName, E.Source, E.Message])); end; on E: Exception do begin ExitCode := 1; Writeln(Format('[%s] %s', [E.ClassName, E.Message])); end; end; end. ================================================ FILE: samples/NodeSample/NodeSample.lpi ================================================ ================================================ FILE: samples/NodeSample/README.md ================================================ Limited support for [Node](https://nodejs.org/en/) [modules](https://nodejs.org/api/modules.html). Blog post: [Node modules with Delphi and Free Pascal](https://tondrej.blogspot.com/2019/01/node-modules-with-delphi-and-free-pascal.html) ================================================ FILE: samples/NodeSample/demo_commonmark.js ================================================ console.log('***** commonmark demo *****'); var commonmark = require('commonmark'); var reader = new commonmark.Parser(); var writer = new commonmark.HtmlRenderer(); var md = 'Hello, *world*!\n\nfrom [chakracore-delphi](https://github.com/tondrej/chakracore-delphi)'; var parsed = reader.parse(md); // parsed is a 'Node' tree // transform parsed if you like... var result = writer.render(parsed); // result is a String console.log('md: ', JSON.stringify(md)); console.log('result: ', JSON.stringify(result)); ================================================ FILE: samples/NodeSample/demo_graphql.js ================================================ console.log('***** graphql demo *****'); var graphql = require('graphql'); var schema = new graphql.GraphQLSchema({ query: new graphql.GraphQLObjectType({ name: 'RootQueryType', fields: { hello: { type: graphql.GraphQLString, resolve() { return 'world'; } } } }) }); function run(query) { graphql.graphql(schema, query).then(result => { console.log('schema: ', JSON.stringify(schema)); console.log('query: ', JSON.stringify(query)); console.info('result: ', JSON.stringify(result)); console.log(); }).catch(e => { console.log('schema: ', JSON.stringify(schema)); console.log('query: ', JSON.stringify(query)); console.error('error: ', JSON.stringify(e)); console.log(); }); }; run('{ hello }'); run('{ boyhowdy }'); // schema error ================================================ FILE: samples/NodeSample/demo_json-query.js ================================================ console.log('***** json-query *****'); var jsonQuery = require('json-query'); var data = { people: [ {name: 'Matt', country: 'NZ'}, {name: 'Pete', country: 'AU'}, {name: 'Mikey', country: 'NZ'} ] }; var query = 'people[*country=NZ].name'; console.log('data: ', JSON.stringify(data)); console.log('query: ', JSON.stringify(query)); console.log('result: ', JSON.stringify(jsonQuery(query, { data: data }))); ================================================ FILE: samples/NodeSample/demo_lodash.js ================================================ console.log('***** lodash demo *****'); var lodash = require('lodash'); var users = [ { 'user': 'fred', 'age': 48 }, { 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }, { 'user': 'barney', 'age': 34 } ]; console.log('users: ', JSON.stringify(users)); console.log('by user: ', JSON.stringify(_.sortBy(users, ['user']))); console.log('by age: ', JSON.stringify(_.sortBy(users, ['age']))); ================================================ FILE: samples/NodeSample/demo_moment.js ================================================ console.log('***** moment demo *****'); var moment = require('moment'); var now = moment(); var fmt = 'dddd MMMM Do YYYY, h:mm:ss a'; console.log(JSON.stringify(now.format(fmt)), JSON.stringify(now.utc().format(fmt)), 'UTC'); ================================================ FILE: samples/Samples.XE.groupproj ================================================  {AB33209C-912B-47E0-91BB-2B9A9F0D3456} Default.Personality.12 ================================================ FILE: samples/Samples.bpg ================================================ #------------------------------------------------------------------------------ VERSION = BWS.01 #------------------------------------------------------------------------------ !ifndef ROOT ROOT = $(MAKEDIR)\.. !endif #------------------------------------------------------------------------------ MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$** DCC = $(ROOT)\bin\dcc32.exe $** BRCC = $(ROOT)\bin\brcc32.exe $** #------------------------------------------------------------------------------ PROJECTS = ChakraCoreTests.exe ChakraCoreTestsUI.exe SimpleHost.exe ChakraCoreHostSample.exe \ WasmSample.exe NodeSample.exe #------------------------------------------------------------------------------ default: $(PROJECTS) #------------------------------------------------------------------------------ ChakraCoreTests.exe: ..\tests\ChakraCoreTests.dpr $(DCC) ChakraCoreTestsUI.exe: ..\tests\ChakraCoreTestsUI.dpr $(DCC) ChakraCoreHostSample.exe: HostSample\ChakraCoreHostSample.dpr $(DCC) SimpleHost.exe: SimpleHostSample\SimpleHost.dpr $(DCC) WasmSample.exe: WasmSample\WasmSample.dpr $(DCC) NodeSample.exe: NodeSample\NodeSample.dpr $(DCC) ================================================ FILE: samples/Samples.lpg ================================================ ================================================ FILE: samples/SimpleHostSample/SimpleHost.XE.dproj ================================================  {01f91de3-a053-4032-ac0c-ba8b9af05f13} SimpleHost.dpr Debug DCC32 12.3 True Win32 Console None true true Base true true Base true ..\..\bin\$(Platform)\$(Config)\SimpleHost.exe ..\..\bin\$(Platform)\$(Config) ..\..\lib\$(Platform)\$(Config) 00400000 vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) x86 ..\..\src;$(DCC_UnitSearchPath) false true false 1 false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 VCLApplication SimpleHost.dpr ..\..\..\samples\SimpleHostSample\scripts\hello.js True False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 SimpleHost © 2021 Ondrej Kelle SimpleHost.exe chakracore-delphi 1.0.0.0 True 12 ================================================ FILE: samples/SimpleHostSample/SimpleHost.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\..\bin\Win32\Debug UnitOutputDir=..\..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\..\src Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers;GR32_DSGN_D7;GR32_D7 Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams=..\..\..\samples\SimpleHostSample\scripts\hello.js HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1031 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=SimpleHost LegalCopyright=© 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=SimpleHost.exe ProductName=chakracore-delphi ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: samples/SimpleHostSample/SimpleHost.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program SimpleHost; {$APPTYPE CONSOLE} {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cthreads, {$endif}{$endif} SysUtils, Classes, Compat, ChakraCoreVersion, ChakraCommon, ChakraCoreUtils, ChakraCoreClasses; {$R *.res} function Console_Log(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := JsUndefinedValue; try if not Assigned(Args) or (ArgCount < 2) then Exit; Writeln(JsStringToUTF8String(Args^[1])); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function LoadFile(const FileName: UnicodeString): UnicodeString; var FileStream: TFileStream; S: UTF8String; begin Result := ''; FileStream := TFileStream.Create(FileName, fmOpenRead); try if FileStream.Size = 0 then Exit; SetLength(S, FileStream.Size); FileStream.Read(S[1], FileStream.Size); Result := UTF8ToString(S); finally FileStream.Free; end; end; procedure Main; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; Console: JsValueRef; begin if ParamCount = 0 then Exit; Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; Console := JsCreateObject; JsSetCallback(Console, 'log', @Console_Log, nil); JsSetProperty(Context.Global, 'console', Console); {$ifdef UNICODE} Context.RunScript(LoadFile(ParamStr(1)), ExtractFileName(Paramstr(1))); {$else} Context.RunScript(LoadFile(UTF8Decode(ParamStr(1))), ExtractFileName(UTF8Decode(Paramstr(1)))); {$endif} finally Context.Free; Runtime.Free; end; end; begin {$ifdef DELPHI2006_UP} ReportMemoryLeaksOnShutdown := True; {$endif} try Main; except on E: EChakraCoreScript do begin ExitCode := 1; Writeln(Format('%s (%d, %d): [%s] %s', [E.ScriptURL, E.Line + 1, E.Column + 1, E.ClassName, E.Message])); end; on E: Exception do begin ExitCode := 1; Writeln(Format('[%s] %s', [E.ClassName, E.Message])); end; end; end. ================================================ FILE: samples/SimpleHostSample/SimpleHost.lpi ================================================ ================================================ FILE: samples/SimpleHostSample/scripts/hello.js ================================================ console.log("Hello, world!"); ================================================ FILE: samples/WasmSample/README.md ================================================ Based on Colin Eberhardt's [Writing WebAssembly By Hand](https://blog.scottlogic.com/2018/04/26/webassembly-by-hand.html) ([code](https://webassembly.studio/?f=ivzzdwn7fcn)) ================================================ FILE: samples/WasmSample/WasmMainData.dfm ================================================ object DataModuleMain: TDataModuleMain OldCreateOrder = False OnCreate = DataModuleCreate Height = 265 Width = 368 object OpenDialog: TOpenDialog DefaultExt = '.js' Filter = 'Javascript files (*.js)|*.js|All files (*.*)|*.*' FilterIndex = 0 Title = 'Open Javascript file' Left = 24 Top = 8 end end ================================================ FILE: samples/WasmSample/WasmMainData.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit WasmMainData; interface {$include common.inc} uses {$ifdef FPC}{$ifdef UNIX} cwstring, {$endif}{$endif} {$ifdef WINDOWS} Windows, {$endif} {$ifdef FPC} LCLIntf, LCLType, {$endif} SysUtils, Classes, Forms, Graphics, Dialogs, {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Compat, ChakraCommon, ChakraCore, ChakraCoreUtils, ChakraCoreClasses, Console; type { TDataModuleMain } TDataModuleMain = class(TDataModule) OpenDialog: TOpenDialog; procedure DataModuleCreate(Sender: TObject); private FCanvas: JsValueRef; FConsole: TConsole; FContext: TChakraCoreContext; FRuntime: TChakraCoreRuntime; FScriptFileName: UnicodeString; FTerminated: Boolean; FThread: TThread; FWasmFileName: UnicodeString; procedure ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel = ilNone); procedure ContextActivate(Sender: TObject); procedure ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); procedure Finalize; function GetActive: Boolean; procedure Initialize; function LoadWasmModule(const FileName: UnicodeString): JsValueRef; procedure RunScript; procedure SetActive(Value: Boolean); public property Active: Boolean read GetActive write SetActive; property ScriptFileName: UnicodeString read FScriptFileName; end; var DataModuleMain: TDataModuleMain; implementation {$R *.dfm} uses WasmMainForm; type { TTaskMessageEx } TTaskMessageEx = class(TTaskMessage) private FDataModule: TDataModuleMain; protected function Process(out ResultValue: JsValueRef): Boolean; override; end; function TTaskMessageEx.Process(out ResultValue: JsValueRef): Boolean; begin Result := FDataModule.FTerminated or inherited Process(ResultValue); end; type { TWasmThread } TWasmThread = class(TThread) private FDataModule: TDataModuleMain; protected procedure Execute; override; public constructor Create(ADataModule: TDataModuleMain); destructor Destroy; override; end; constructor TWasmThread.Create(ADataModule: TDataModuleMain); begin FDataModule := ADataModule; FDataModule.FThread := Self; FreeOnTerminate := True; inherited Create(False); end; destructor TWasmThread.Destroy; begin FDataModule.FThread := nil; inherited Destroy; end; procedure TWasmThread.Execute; begin FDataModule.Initialize; try FDataModule.RunScript; finally FDataModule.Finalize; end; end; function LoadFile(const FileName: UnicodeString): UnicodeString; var FileStream: TFileStream; S: UTF8String; begin Result := ''; FileStream := TFileStream.Create(FileName, fmOpenRead); try if FileStream.Size = 0 then Exit; SetLength(S, FileStream.Size); FileStream.Read(S[1], FileStream.Size); Result := UTF8ToString(S); finally FileStream.Free; end; end; function PostTimedTask(Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer; RepeatCount: Integer): JsValueRef; var DataModule: TDataModuleMain absolute CallbackState; AMessage: TTaskMessageEx; Delay: Cardinal; FuncArgs: array of JsValueRef; I: Integer; begin Result := JsUndefinedValue; if DataModule.FTerminated then Exit; if ArgCount < 2 then // thisarg, function to call, optional: delay, function args raise Exception.Create('Invalid arguments'); if ArgCount >= 3 then Delay := JsNumberToInt(Args^[2]) else Delay := 0; if ArgCount >= 4 then begin SetLength(FuncArgs, ArgCount - 3); for I := 0 to ArgCount - 4 do FuncArgs[I] := Args^[I + 3]; end; AMessage := TTaskMessageEx.Create(DataModule.FContext, Args^[1], Args^[0], FuncArgs, Delay, RepeatCount); try AMessage.FDataModule := DataModule; DataModule.FContext.PostMessage(AMessage); except AMessage.Free; raise; end; end; function Canvas_FillRect_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := JsUndefinedValue; try FormMain.FillRect(JsNumberToInt(Args^[1]), JsNumberToInt(Args^[2]), JsNumbertoInt(Args^[3]), JsNumberToInt(Args^[4]), JsStringToUnicodeString(JsGetProperty(Args^[0], 'fillStyle'))); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function LoadWasm_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var DataModule: TDataModuleMain absolute CallbackState; begin Result := JsUndefinedValue; try DataModule.FWasmFileName := ExtractFilePath(DataModule.FScriptFileName) + JsStringToUnicodeString(Args^[1]); Result := DataModule.LoadWasmModule(DataModule.FWasmFileName); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function SetInterval_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := JsUndefinedValue; try Result := PostTimedTask(Args, ArgCount, CallbackState, -1); // repeat endlessly except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function SetTimeout_Callback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := JsUndefinedValue; try Result := PostTimedTask(Args, ArgCount, CallbackState, 1); // run once except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; procedure TDataModuleMain.DataModuleCreate(Sender: TObject); begin FScriptFileName := ParamStr(1); end; procedure TDataModuleMain.ConsoleLog(Sender: TObject; const Text: UnicodeString; Level: TInfoLevel); var P: PUnicodeChar; L: Integer; begin P := nil; try L := Length(Text); P := AllocMem((L + 1) * SizeOf(UnicodeChar)); if L > 0 then Move(Text[1], P^, L * SizeOf(UnicodeChar)); PostMessage(FormMain.Handle, WM_CONSOLELOG, WPARAM(P), 0); except if Assigned(P) then FreeMem(P); raise; end; end; procedure TDataModuleMain.ContextActivate(Sender: TObject); begin // expose additional functions JsSetCallback(FContext.Global, 'setTimeout', @SetTimeout_Callback, Self); JsSetCallback(FContext.Global, 'setInterval', @SetInterval_Callback, Self); JsSetCallback(FContext.Global, 'loadWasm', @LoadWasm_Callback, Self); // project TConsole class so scripts can create instances, e.g. var c = new Console(); TConsole.Project; // expose global.console FConsole := TConsole.Create; JsSetProperty(FContext.Global, 'console', FConsole.Instance); FCanvas := JsCreateObject; JsSetProperty(FCanvas, 'fillStyle', StringToJsString('black')); JsSetCallback(FCanvas, 'fillRect', @Canvas_FillRect_Callback, Self); JsSetProperty(FContext.Global, 'ctx', FCanvas); end; procedure TDataModuleMain.ContextNativeObjectCreated(Sender: TObject; NativeObject: TNativeObject); begin if NativeObject is TConsole then TConsole(NativeObject).OnLog := ConsoleLog; end; function TDataModuleMain.LoadWasmModule(const FileName: UnicodeString): JsValueRef; var Buffer: TChakraCoreNativeArrayBuffer; FileStream: TFileStream; begin Result := JsUndefinedValue; FileStream := TFileStream.Create(FileName, fmOpenRead); try Buffer := TChakraCoreNativeArrayBuffer.Create(FileStream.Size); try FileStream.ReadBuffer(Buffer.Buffer^, Buffer.BufferSize); Result := Buffer.Handle; ConsoleLog(FConsole, Format('Loaded WebAssembly file ''%s''', [FWasmFileName])); except Buffer.Free; raise; end; finally FileStream.Free; end; end; procedure TDataModuleMain.RunScript; var Script: UnicodeString; begin try Script := LoadFile(FScriptFileName); ConsoleLog(FConsole, Format('Loaded Javascript file ''%s''', [FScriptFileName])); FContext.RunScript(Script, FScriptFileName); except on E: EChakraCoreScript do ConsoleLog(FConsole, Format('%s (%d, %d): [%s] %s', [E.ScriptURL, E.Line + 1, E.Column + 1, E.ClassName, E.Message])); on E: Exception do ConsoleLog(FConsole, Format('[%s] %s', [E.ClassName, E.Message])); end; end; procedure TDataModuleMain.Finalize; begin FreeAndNil(FConsole); FreeAndNil(FContext); FreeAndNil(FRuntime); end; function TDataModuleMain.GetActive: Boolean; begin Result := Assigned(FThread); end; procedure TDataModuleMain.Initialize; begin FRuntime := TChakraCoreRuntime.Create([ccroEnableExperimentalFeatures, ccroDispatchSetExceptionsToDebugger]); FContext := TChakraCoreContext.Create(FRuntime); FContext.OnActivate := ContextActivate; FContext.OnNativeObjectCreated := ContextNativeObjectCreated; end; procedure TDataModuleMain.SetActive(Value: Boolean); begin if Value <> Active then begin FTerminated := not Value; if Value then begin if FScriptFileName = '' then begin OpenDialog.FileName := ''; if OpenDialog.Execute then FScriptFileName := OpenDialog.FileName; end; FThread := TWasmThread.Create(Self); end; end; end; end. ================================================ FILE: samples/WasmSample/WasmMainForm.dfm ================================================ object FormMain: TFormMain Left = 192 Top = 124 Width = 464 Height = 639 Caption = 'FormMain' Color = clBtnFace Constraints.MinHeight = 639 Constraints.MinWidth = 464 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = True ShowHint = True OnCloseQuery = FormCloseQuery OnCreate = FormCreate DesignSize = ( 448 600) PixelsPerInch = 96 TextHeight = 13 object PaintBox: TPaintBox Left = 4 Top = 36 Width = 440 Height = 440 Anchors = [akLeft, akTop, akRight, akBottom] OnPaint = PaintBoxPaint end object MemoLog: TMemo Left = 4 Top = 480 Width = 440 Height = 109 Anchors = [akLeft, akRight, akBottom] Font.Charset = ANSI_CHARSET Font.Color = clWindowText Font.Height = -12 Font.Name = 'Consolas' Font.Style = [] ParentColor = True ParentFont = False ReadOnly = True ScrollBars = ssBoth TabOrder = 0 end object ToolBar: TToolBar Left = 0 Top = 0 Width = 448 Height = 41 ButtonHeight = 36 ButtonWidth = 29 Caption = 'ToolBar' Images = ImageList ShowCaptions = True TabOrder = 1 object ToolButtonStartStop: TToolButton Left = 0 Top = 2 Action = ActionStartStop end end object ImageList: TImageList Left = 80 Top = 56 Bitmap = { 494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000001000000001002000000000000010 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000001810100008000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000800000028302000080000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000008000002AB72A000284020000800000000000000000 00000000000000000000000000000000000000000000000000000000AA000000 AA000000AA000000AA000000AA000000AA000000AA000000AA000000AA000000 AA000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C837002AB72A0002840200008000000000 00000000000000000000000000000000000000000000000000000000AA006B6B FF005F5FFF005353FF004747FF003B3BFF002F2FFF002424FF001818FF000C0C FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C837002AB72A00028402000080 00000000000000000000000000000000000000000000000000000000AA007676 FF006B6BFF005F5FFF005353FF004747FF003B3BFF002F2FFF002424FF001818 FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C8370037C837002AB72A000284 02000080000000000000000000000000000000000000000000000000AA008282 FF007676FF006B6BFF005F5FFF005353FF004747FF003B3BFF002F2FFF002424 FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C8370037C8370037C8370029B6 29000283020000820000000000000000000000000000000000000000AA008E8E FF008282FF007676FF006B6BFF005F5FFF005353FF004747FF003B3BFF002F2F FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C8370037C8370037C8370029B6 29000283020000820000000000000000000000000000000000000000AA009A9A FF008E8EFF008282FF007676FF006B6BFF005F5FFF005353FF004747FF003B3B FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C8370037C837002AB72A000283 02000080000000000000000000000000000000000000000000000000AA00A6A6 FF009A9AFF008E8EFF008282FF007676FF006B6BFF005F5FFF005353FF004747 FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C8370037C837002AB72A00028302000080 00000000000000000000000000000000000000000000000000000000AA00B2B2 FF00A6A6FF009A9AFF008E8EFF008282FF007676FF006B6BFF005F5FFF005353 FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000080000037C837002AB72A0002830200008000000000 00000000000000000000000000000000000000000000000000000000AA00BDBD FF00B2B2FF00A6A6FF009A9AFF008E8EFF008282FF007676FF006B6BFF005F5F FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000008000002AB72A000283020000800000000000000000 00000000000000000000000000000000000000000000000000000000AA00C9C9 FF00BDBDFF00B2B2FF00A6A6FF009A9AFF008E8EFF008282FF007676FF006B6B FF000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000800000028302000080000000000000000000000000 00000000000000000000000000000000000000000000000000000000AA000000 AA000000AA000000AA000000AA000000AA000000AA000000AA000000AA000000 AA000000AA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000001810100008000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000100000000100010000000000800000000000000000000000 000000000000000000000000FFFFFF00FFFFFFFF00000000FCFFFFFF00000000 FC7FFFFF00000000FC3FC00700000000FC1FC00700000000FC0FC00700000000 FC07C00700000000FC03C00700000000FC03C00700000000FC07C00700000000 FC0FC00700000000FC1FC00700000000FC3FC00700000000FC7FC00700000000 FCFFFFFF00000000FFFFFFFF0000000000000000000000000000000000000000 000000000000} end object ActionList: TActionList Images = ImageList Left = 120 Top = 56 object ActionStartStop: TAction Caption = 'Start' ImageIndex = 0 ShortCut = 120 OnExecute = ActionStartStopExecute OnUpdate = ActionStartStopUpdate end end end ================================================ FILE: samples/WasmSample/WasmMainForm.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit WasmMainForm; interface {$include common.inc} uses {$ifdef FPC} LCLIntf, LCLType, LMessages, {$else} Windows, {$endif} SysUtils, Variants, Classes, Types, Messages, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ToolWin, ComCtrls, ActnList, ImgList, Compat; const Dimension = 50; WM_CONSOLELOG = WM_USER + 1; type TWMConsoleLog = record Msg: Cardinal; {$ifdef CPU64} UnusedMsg: Cardinal; {$endif CPU64} Text: PWideChar; Unusedl: NativeInt; Result: LRESULT; end; { TFormMain } TFormMain = class(TForm) ActionList: TActionList; ActionStartStop: TAction; ImageList: TImageList; MemoLog: TMemo; PaintBox: TPaintBox; ToolBar: TToolBar; ToolButtonStartStop: TToolButton; procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure FormCreate(Sender: TObject); procedure ActionStartStopExecute(Sender: TObject); procedure ActionStartStopUpdate(Sender: TObject); procedure PaintBoxPaint(Sender: TObject); private FGame: array[0..Dimension - 1, 0..Dimension - 1] of Boolean; procedure ApplicationIdle(Sender: TObject; var Done: Boolean); procedure WMConsoleLog(var Message: TWMConsoleLog); message WM_CONSOLELOG; public procedure FillRect(X, Y, W, H: Integer; const Style: string); end; var FormMain: TFormMain; implementation {$R *.dfm} uses ChakraCore, ChakraCoreVersion, ChakraCoreUtils, WasmMainData; procedure TFormMain.FillRect(X, Y, W, H: Integer; const Style: string); var I, J: Integer; CellValue: Boolean; begin CellValue := Style = 'green'; if not CellValue and (W = Dimension) and (H = Dimension) then begin FillChar(FGame, SizeOf(FGame), 0); Exit; end; for I := X to X + W - 1 do for J := Y to Y + H - 1 do FGame[I, J] := CellValue; {$ifndef LINUX} PaintBox.Invalidate; {$endif !LINUX} end; procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := True; DataModuleMain.Active := False; end; procedure TFormMain.FormCreate(Sender: TObject); begin PaintBox.Width := ClientWidth - 8; MemoLog.Width := ClientWidth - 8; DoubleBuffered := True; Caption := Application.Title; {$ifdef LINUX} Application.OnIdle := ApplicationIdle; {$endif LINUX} MemoLog.Lines.Add(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); MemoLog.Lines.Add(Format('Built with %s', [GetBuildInfoString])); MemoLog.Lines.Add(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); MemoLog.Lines.Add(''); end; procedure TFormMain.ActionStartStopExecute(Sender: TObject); begin DataModuleMain.Active := not DataModuleMain.Active; end; procedure TFormMain.ActionStartStopUpdate(Sender: TObject); const StartStopCaptions: array[Boolean] of string = ('Start', 'Stop'); StartStopImageIndexes: array[Boolean] of Integer = (0, 1); var Action: TAction absolute Sender; begin Action.Caption := StartStopCaptions[DataModuleMain.Active]; Action.Hint := StartStopCaptions[DataModuleMain.Active]; Action.ImageIndex := StartStopImageIndexes[DataModuleMain.Active]; end; procedure TFormMain.PaintBoxPaint(Sender: TObject); var PaintBox: TPaintBox absolute Sender; W, H, X, Y: Integer; R: TRect; begin PaintBox.Canvas.Brush.Color := clBlack; PaintBox.Canvas.FillRect(PaintBox.ClientRect); PaintBox.Canvas.Brush.Color := clGreen; W := PaintBox.ClientWidth div Dimension; H := PaintBox.ClientHeight div Dimension; R := Rect(0, 0, W, H); for Y := 0 to Dimension - 1 do begin R.Left := 0; R.Right := W; for X := 0 to Dimension - 1 do begin if FGame[X, Y] then PaintBox.Canvas.FillRect(R); OffsetRect(R, W, 0); end; OffsetRect(R, 0, H); end; end; procedure TFormMain.ApplicationIdle(Sender: TObject; var Done: Boolean); begin PaintBox.Invalidate; end; procedure TFormMain.WMConsoleLog(var Message: TWMConsoleLog); begin try // inherited; MemoLog.Lines.Add(Message.Text); finally if Assigned(Message.Text) then FreeMem(Message.Text); end; end; end. ================================================ FILE: samples/WasmSample/WasmSample.XE.dproj ================================================  {6508e7aa-0c87-481c-ae23-258f81176312} WasmSample.dpr Debug DCC32 12.3 True Win32 Application VCL true true Base true true Base true ..\..\bin\$(Platform)\$(Config)\WasmSample.exe ..\..\bin\$(Platform)\$(Config) ..\..\lib\$(Platform)\$(Config) 00400000 vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) x86 ..\..\src;..\HostSample;$(DCC_UnitSearchPath) false true false 1 false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource
DataModuleMain
TDataModule
FormMain
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication WasmSample.dpr ..\..\..\samples\WasmSample\scripts\main.js ..\..\..\samples\WasmSample\scripts\main.wasm True False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 WasmSample © 2021 Ondrej Kelle WasmSample chakracore-delphi 1.0.0.0 True 12
================================================ FILE: samples/WasmSample/WasmSample.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=0 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\..\bin\Win32\Debug UnitOutputDir=..\..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\..\src;..\..\samples\HostSample Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams=..\..\..\samples\WasmSample\scripts\main.js HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=WasmSample LegalCopyright=© 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=WasmSample.exe ProductName=chakracore-delphi ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src;..\..\samples\HostSample [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: samples/WasmSample/WasmSample.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program WasmSample; {$include common.inc} uses {$ifdef FPC} {$apptype GUI} {$ifdef UNIX} cthreads, {$endif UNIX} Interfaces, {$endif FPC} Classes, SysUtils, Forms, Compat, ChakraCoreVersion, ChakraCoreUtils, WasmMainData in 'WasmMainData.pas' {DataModuleMain: TDataModule}, WasmMainForm in 'WasmMainForm.pas' {FormMain}; {$R *.res} type UnicodeStringDynArray = array of UnicodeString; function ParamStrings: UnicodeStringDynArray; var I: Integer; begin Result := nil; SetLength(Result, ParamCount); for I := 1 to ParamCount do Result[I - 1] := UnicodeString(ParamStr(I)); end; begin {$ifdef DELPHI2006_UP} ReportMemoryLeaksOnShutdown := True; {$endif DELPHI2006_UP} {$ifdef FPC} RequireDerivedFormResource := True; {$endif FPC} Application.Title := 'ChakraCore WebAssembly Sample'; Application.Initialize; Application.CreateForm(TDataModuleMain, DataModuleMain); Application.CreateForm(TFormMain, FormMain); Application.Run; end. ================================================ FILE: samples/WasmSample/WasmSample.lpi ================================================ <Scaled Value="True"/> <ResourceType Value="res"/> <Icon Value="0"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="1"/> <StringTable InternalName="WasmSample" LegalCopyright="© 2021 Ondrej Kelle" OriginalFilename="WasmSample"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Debug" Default="True"/> <Item2 Name="Release"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="WasmSample"/> </Target> <SearchPaths> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <CommandLineParams Value="../../../samples/WasmSample/scripts/main.js"/> </local> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="Debug"> <local> <CommandLineParams Value="../../../samples/WasmSample/scripts/main.js"/> </local> </Mode0> </Modes> </RunParams> <RequiredPackages Count="2"> <Item1> <PackageName Value="LCL"/> </Item1> <Item2> <PackageName Value="LCLBase"/> </Item2> </RequiredPackages> <Units Count="3"> <Unit0> <Filename Value="WasmSample.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="WasmMainData.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="DataModuleMain"/> <HasResources Value="True"/> <ResourceBaseClass Value="DataModule"/> </Unit1> <Unit2> <Filename Value="WasmMainForm.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FormMain"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit2> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)/WasmSample"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);../../src"/> <OtherUnitFiles Value="../../src;../../samples/HostSample"/> <UnitOutputDirectory Value="../../lib/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> </SearchPaths> <Parsing> <SyntaxOptions> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <TrashVariables Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="4"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> <Item4> <Name Value="EChakraCore"/> </Item4> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: samples/WasmSample/scripts/main.js ================================================ const DIMENSIONS = 50; const verbose = false; // true; const rand = () => Math.floor(Math.random() * DIMENSIONS); WebAssembly.instantiate(loadWasm('main.wasm'), { console: { log: (x, y) => console.log(x, y) } }).then(results => { const game = results.instance.exports; for (let i = 0; i < 400; i++) { game.setCell(rand(), rand(), 1); } let step = 0; const render = () => { let count = 0; ctx.fillStyle = "black"; ctx.fillRect(0, 0, DIMENSIONS, DIMENSIONS); ctx.fillStyle = "green"; for (let y = 0; y < DIMENSIONS; y++) { for (let x = 0; x < DIMENSIONS; x++) { if (game.getCell(x, y) > 0) { ctx.fillRect(x, y, 1, 1); count++; } } } if (verbose) { console.log('Step %d: %d alive', step++, count); } }; setInterval(() => { game.tick(); render(); }, 50); }); ================================================ FILE: src/ChakraCommon.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to host Chakra. /// /// This file contains the common API set shared among all Chakra releases. For Windows-specific /// releases, see chakrart.h. /// \file /// \brief The base Chakra hosting API. /// /// This file contains a flat C API layer. This is the API exported by chakra.dll. unit ChakraCommon; {$include common.inc} {$minenumsize 4} interface uses Compat; type bool = ByteBool; Psize_t = ^size_t; size_t = NativeUInt; JsHandle = ^_JsHandle; _JsHandle = record end; ChakraCookie = UIntPtr; ChakraBytePtr = PByte; /// <summary> /// An error code returned from a Chakra hosting API. /// </summary> JsErrorCode = ( /// <summary> /// Success error code. /// </summary> JsNoError = 0, /// <summary> /// Category of errors that relates to incorrect usage of the API itself. /// </summary> JsErrorCategoryUsage = $10000, /// <summary> /// An argument to a hosting API was invalid. /// </summary> JsErrorInvalidArgument, /// <summary> /// An argument to a hosting API was null in a context where null is not allowed. /// </summary> JsErrorNullArgument, /// <summary> /// The hosting API requires that a context be current, but there is no current context. /// </summary> JsErrorNoCurrentContext, /// <summary> /// The engine is in an exception state and no APIs can be called until the exception is /// cleared. /// </summary> JsErrorInExceptionState, /// <summary> /// A hosting API is not yet implemented. /// </summary> JsErrorNotImplemented, /// <summary> /// A hosting API was called on the wrong thread. /// </summary> JsErrorWrongThread, /// <summary> /// A runtime that is still in use cannot be disposed. /// </summary> JsErrorRuntimeInUse, /// <summary> /// A bad serialized script was used, or the serialized script was serialized by a /// different version of the Chakra engine. /// </summary> JsErrorBadSerializedScript, /// <summary> /// The runtime is in a disabled state. /// </summary> JsErrorInDisabledState, /// <summary> /// Runtime does not support reliable script interruption. /// </summary> JsErrorCannotDisableExecution, /// <summary> /// A heap enumeration is currently underway in the script context. /// </summary> JsErrorHeapEnumInProgress, /// <summary> /// A hosting API that operates on object values was called with a non-object value. /// </summary> JsErrorArgumentNotObject, /// <summary> /// A script context is in the middle of a profile callback. /// </summary> JsErrorInProfileCallback, /// <summary> /// A thread service callback is currently underway. /// </summary> JsErrorInThreadServiceCallback, /// <summary> /// Scripts cannot be serialized in debug contexts. /// </summary> JsErrorCannotSerializeDebugScript, /// <summary> /// The context cannot be put into a debug state because it is already in a debug state. /// </summary> JsErrorAlreadyDebuggingContext, /// <summary> /// The context cannot start profiling because it is already profiling. /// </summary> JsErrorAlreadyProfilingContext, /// <summary> /// Idle notification given when the host did not enable idle processing. /// </summary> JsErrorIdleNotEnabled, /// <summary> /// The context did not accept the enqueue callback. /// </summary> JsCannotSetProjectionEnqueueCallback, /// <summary> /// Failed to start projection. /// </summary> JsErrorCannotStartProjection, /// <summary> /// The operation is not supported in an object before collect callback. /// </summary> JsErrorInObjectBeforeCollectCallback, /// <summary> /// Object cannot be unwrapped to IInspectable pointer. /// </summary> JsErrorObjectNotInspectable, /// <summary> /// A hosting API that operates on symbol property ids but was called with a non-symbol property id. /// The error code is returned by JsGetSymbolFromPropertyId if the function is called with non-symbol property id. /// </summary> JsErrorPropertyNotSymbol, /// <summary> /// A hosting API that operates on string property ids but was called with a non-string property id. /// The error code is returned by existing JsGetPropertyNamefromId if the function is called with non-string property id. /// </summary> JsErrorPropertyNotString, /// <summary> /// Module evaluation is called in wrong context. /// </summary> JsErrorInvalidContext, /// <summary> /// Module evaluation is called in wrong context. /// </summary> JsInvalidModuleHostInfoKind, /// <summary> /// Module was parsed already when JsParseModuleSource is called. /// </summary> JsErrorModuleParsed, /// <summary> /// Module was evaluated already when JsModuleEvaluation is called. /// </summary> JsErrorModuleEvaluated, /// <summary> /// Argument passed to JsCreateWeakReference is a primitive that is not managed by the GC. /// No weak reference is required, the value will never be collected. /// </summary> JsNoWeakRefRequired, /// <summary> /// The <c>Promise</c> object is still in the pending state. /// </summary> JsErrorPromisePending, /// <summary> /// Module was not yet evaluated when JsGetModuleNamespace was called. /// </summary> JsErrorModuleNotEvaluated, /// <summary> /// Category of errors that relates to errors occurring within the engine itself. /// </summary> JsErrorCategoryEngine = $20000, /// <summary> /// The Chakra engine has run out of memory. /// </summary> JsErrorOutOfMemory, /// <summary> /// The Chakra engine failed to set the Floating Point Unit state. /// </summary> JsErrorBadFPUState, /// <summary> /// Category of errors that relates to errors in a script. /// </summary> JsErrorCategoryScript = $30000, /// <summary> /// A JavaScript exception occurred while running a script. /// </summary> JsErrorScriptException, /// <summary> /// JavaScript failed to compile. /// </summary> JsErrorScriptCompile, /// <summary> /// A script was terminated due to a request to suspend a runtime. /// </summary> JsErrorScriptTerminated, /// <summary> /// A script was terminated because it tried to use <c>eval</c> or <c>function</c> and eval /// was disabled. /// </summary> JsErrorScriptEvalDisabled, /// <summary> /// Category of errors that are fatal and signify failure of the engine. /// </summary> JsErrorCategoryFatal = $40000, /// <summary> /// A fatal error in the engine has occurred. /// </summary> JsErrorFatal, /// <summary> /// A hosting API was called with object created on different javascript runtime. /// </summary> JsErrorWrongRuntime, /// <summary> /// Category of errors that are related to failures during diagnostic operations. /// </summary> JsErrorCategoryDiagError = $50000, /// <summary> /// The object for which the debugging API was called was not found /// </summary> JsErrorDiagAlreadyInDebugMode, /// <summary> /// The debugging API can only be called when VM is in debug mode /// </summary> JsErrorDiagNotInDebugMode, /// <summary> /// The debugging API can only be called when VM is at a break /// </summary> JsErrorDiagNotAtBreak, /// <summary> /// Debugging API was called with an invalid handle. /// </summary> JsErrorDiagInvalidHandle, /// <summary> /// The object for which the debugging API was called was not found /// </summary> JsErrorDiagObjectNotFound, /// <summary> /// VM was unable to perform the request action /// </summary> JsErrorDiagUnableToPerformAction ); /// <summary> /// A handle to a Chakra runtime. /// </summary> /// <remarks> /// <para> /// Each Chakra runtime has its own independent execution engine, JIT compiler, and garbage /// collected heap. As such, each runtime is completely isolated from other runtimes. /// </para> /// <para> /// Runtimes can be used on any thread, but only one thread can call into a runtime at any /// time. /// </para> /// <para> /// NOTE: A <c>JsRuntimeHandle</c>, unlike other object references in the Chakra hosting API, /// is not garbage collected since it contains the garbage collected heap itself. A runtime /// will continue to exist until <c>JsDisposeRuntime</c> is called. /// </para> /// </remarks> JsRuntimeHandle = JsHandle; const /// <summary> /// An invalid runtime handle. /// </summary> JS_INVALID_RUNTIME_HANDLE = JsRuntimeHandle(nil); /// <summary> /// A reference to an object owned by the Chakra garbage collector. /// </summary> /// <remarks> /// A Chakra runtime will automatically track <c>JsRef</c> references as long as they are /// stored in local variables or in parameters (i.e. on the stack). Storing a <c>JsRef</c> /// somewhere other than on the stack requires calling <c>JsAddRef</c> and <c>JsRelease</c> to /// manage the lifetime of the object, otherwise the garbage collector may free the object /// while it is still in use. /// </remarks> type JsRef = JsHandle; const /// <summary> /// An invalid reference. /// </summary> JS_INVALID_REFERENCE = JsRef(nil); type /// <summary> /// A reference to a script context. /// </summary> /// <remarks> /// <para> /// Each script context contains its own global object, distinct from the global object in /// other script contexts. /// </para> /// <para> /// Many Chakra hosting APIs require an "active" script context, which can be set using /// <c>JsSetCurrentContext</c>. Chakra hosting APIs that require a current context to be set /// will note that explicitly in their documentation. /// </para> /// </remarks> JsContextRef = JsRef; PJsValueRef = ^JsValueRef; /// <summary> /// A reference to a JavaScript value. /// </summary> /// <remarks> /// A JavaScript value is one of the following types of values: undefined, null, Boolean, /// string, number, or object. /// </remarks> JsValueRef = JsRef; /// <summary> /// A cookie that identifies a script for debugging purposes. /// </summary> JsSourceContext = ChakraCookie; const /// <summary> /// An empty source context. /// </summary> JS_SOURCE_CONTEXT_NONE = JsSourceContext(-1); type /// <summary> /// A property identifier. /// </summary> /// <remarks> /// Property identifiers are used to refer to properties of JavaScript objects instead of using /// strings. /// </remarks> JsPropertyIdRef = type JsRef; /// <summary> /// Attributes of a runtime. /// </summary> JsRuntimeAttributes = Cardinal; const /// <summary> /// No special attributes. /// </summary> JsRuntimeAttributeNone = $00000000; /// <summary> /// The runtime will not do any work (such as garbage collection) on background threads. /// </summary> JsRuntimeAttributeDisableBackgroundWork = $00000001; /// <summary> /// The runtime should support reliable script interruption. This increases the number of /// places where the runtime will check for a script interrupt request at the cost of a /// small amount of runtime performance. /// </summary> JsRuntimeAttributeAllowScriptInterrupt = $00000002; /// <summary> /// Host will call <c>JsIdle</c>, so enable idle processing. Otherwise, the runtime will /// manage memory slightly more aggressively. /// </summary> JsRuntimeAttributeEnableIdleProcessing = $00000004; /// <summary> /// Runtime will not generate native code. /// </summary> JsRuntimeAttributeDisableNativeCodeGeneration = $00000008; /// <summary> /// Using <c>eval</c> or <c>function</c> constructor will throw an exception. /// </summary> JsRuntimeAttributeDisableEval = $00000010; /// <summary> /// Runtime will enable all experimental features. /// </summary> JsRuntimeAttributeEnableExperimentalFeatures = $00000020; /// <summary> /// Calling <c>JsSetException</c> will also dispatch the exception to the script debugger /// (if any) giving the debugger a chance to break on the exception. /// </summary> JsRuntimeAttributeDispatchSetExceptionsToDebugger = $00000040; /// <summary> /// Disable Failfast fatal error on OOM /// </summary> JsRuntimeAttributeDisableFatalOnOOM = $00000080; /// <summary> /// Runtime will not allocate executable code pages /// This also implies that Native Code generation will be turned off /// Note that this will break JavaScript stack decoding in tools // like WPA since they rely on allocation of unique thunks to // interpret each function and allocation of those thunks will be // disabled as well /// </summary> JsRuntimeAttributeDisableExecutablePageAllocation = $00000100; type PJsTypedArrayType = ^JsTypedArrayType; /// <summary> /// The type of a typed JavaScript array. /// </summary> JsTypedArrayType = ( /// <summary> /// An int8 array. /// </summary> JsArrayTypeInt8, /// <summary> /// An uint8 array. /// </summary> JsArrayTypeUint8, /// <summary> /// An uint8 clamped array. /// </summary> JsArrayTypeUint8Clamped, /// <summary> /// An int16 array. /// </summary> JsArrayTypeInt16, /// <summary> /// An uint16 array. /// </summary> JsArrayTypeUint16, /// <summary> /// An int32 array. /// </summary> JsArrayTypeInt32, /// <summary> /// An uint32 array. /// </summary> JsArrayTypeUint32, /// <summary> /// A float32 array. /// </summary> JsArrayTypeFloat32, /// <summary> /// A float64 array. /// </summary> JsArrayTypeFloat64 ); /// <summary> /// Allocation callback event type. /// </summary> JsMemoryEventType = ( /// <summary> /// Indicates a request for memory allocation. /// </summary> JsMemoryAllocate = 0, /// <summary> /// Indicates a memory freeing event. /// </summary> JsMemoryFree = 1, /// <summary> /// Indicates a failed allocation event. /// </summary> JsMemoryFailure = 2 ); /// <summary> /// Attribute mask for JsParseScriptWithAttributes /// </summary> JsParseScriptAttribute = ( /// <summary> /// Default attribute /// </summary> // JsParseScriptAttributeNone = $0, /// <summary> /// Specified script is internal and non-user code. Hidden from debugger /// </summary> JsParseScriptAttributeLibraryCode, // = $1, /// <summary> /// ChakraCore assumes ExternalArrayBuffer is Utf8 by default. /// This one needs to be set for Utf16 /// </summary> JsParseScriptAttributeArrayBufferIsUtf16Encoded // = $2 ); JsParseScriptAttributes = set of JsParseScriptAttribute; /// <summary> /// Type enumeration of a JavaScript property /// </summary> JsPropertyIdType = ( /// <summary> /// Type enumeration of a JavaScript string property /// </summary> JsPropertyIdTypeString, /// <summary> /// Type enumeration of a JavaScript symbol property /// </summary> JsPropertyIdTypeSymbol ); /// <summary> /// The JavaScript type of a JsValueRef. /// </summary> JsValueType = ( /// <summary> /// The value is the <c>undefined</c> value. /// </summary> JsUndefined = 0, /// <summary> /// The value is the <c>null</c> value. /// </summary> JsNull = 1, /// <summary> /// The value is a JavaScript number value. /// </summary> JsNumber = 2, /// <summary> /// The value is a JavaScript string value. /// </summary> JsString = 3, /// <summary> /// The value is a JavaScript Boolean value. /// </summary> JsBoolean = 4, /// <summary> /// The value is a JavaScript object value. /// </summary> JsObject = 5, /// <summary> /// The value is a JavaScript function object value. /// </summary> JsFunction = 6, /// <summary> /// The value is a JavaScript error object value. /// </summary> JsError = 7, /// <summary> /// The value is a JavaScript array object value. /// </summary> JsArray = 8, /// <summary> /// The value is a JavaScript symbol value. /// </summary> JsSymbol = 9, /// <summary> /// The value is a JavaScript ArrayBuffer object value. /// </summary> JsArrayBuffer = 10, /// <summary> /// The value is a JavaScript typed array object value. /// </summary> JsTypedArray = 11, /// <summary> /// The value is a JavaScript DataView object value. /// </summary> JsDataView = 12 ); /// <summary> /// User implemented callback routine for memory allocation events /// </summary> /// <remarks> /// Use <c>JsSetRuntimeMemoryAllocationCallback</c> to register this callback. /// </remarks> /// <param name="callbackState"> /// The state passed to <c>JsSetRuntimeMemoryAllocationCallback</c>. /// </param> /// <param name="allocationEvent">The type of type allocation event.</param> /// <param name="allocationSize">The size of the allocation.</param> /// <returns> /// For the <c>JsMemoryAllocate</c> event, returning <c>true</c> allows the runtime to continue /// with the allocation. Returning false indicates the allocation request is rejected. The /// return value is ignored for other allocation events. /// </returns> JsMemoryAllocationCallback = function(callbackState: Pointer; allocationEvent: JsMemoryEventType; allocationSize: size_t): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A callback called before collection. /// </summary> /// <remarks> /// Use <c>JsSetBeforeCollectCallback</c> to register this callback. /// </remarks> /// <param name="callbackState">The state passed to <c>JsSetBeforeCollectCallback</c>.</param> JsBeforeCollectCallback = procedure(callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A callback called before collecting an object. /// </summary> /// <remarks> /// Use <c>JsSetObjectBeforeCollectCallback</c> to register this callback. /// </remarks> /// <param name="ref">The object to be collected.</param> /// <param name="callbackState">The state passed to <c>JsSetObjectBeforeCollectCallback</c>.</param> JsObjectBeforeCollectCallback = procedure(ref: JsRef; callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A background work item callback. /// </summary> /// <remarks> /// This is passed to the host's thread service (if provided) to allow the host to /// invoke the work item callback on the background thread of its choice. /// </remarks> /// <param name="callbackState">Data argument passed to the thread service.</param> JsBackgroundWorkItemCallback = procedure(callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A thread service callback. /// </summary> /// <remarks> /// The host can specify a background thread service when calling <c>JsCreateRuntime</c>. If /// specified, then background work items will be passed to the host using this callback. The /// host is expected to either begin executing the background work item immediately and return /// true or return false and the runtime will handle the work item in-thread. /// </remarks> /// <param name="callback">The callback for the background work item.</param> /// <param name="callbackState">The data argument to be passed to the callback.</param> JsThreadServiceCallback = function(callback: JsBackgroundWorkItemCallback; callbackState: Pointer): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Called by the runtime when it is finished with all resources related to the script execution. /// The caller should free the source if loaded, the byte code, and the context at this time. /// </summary> /// <param name="sourceContext">The context passed to Js[Parse|Run]SerializedScriptWithCallback</param> JsSerializedScriptUnloadCallback = procedure(sourceContext: JsSourceContext); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A finalizer callback. /// </summary> /// <param name="data"> /// The external data that was passed in when creating the object being finalized. /// </param> JsFinalizeCallback = procedure(data: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A function callback. /// </summary> /// <param name="callee"> /// A function object that represents the function being invoked. /// </param> /// <param name="isConstructCall">Indicates whether this is a regular call or a 'new' call.</param> /// <param name="arguments">The arguments to the call.</param> /// <param name="argumentCount">The number of arguments.</param> /// <param name="callbackState"> /// The state passed to <c>JsCreateFunction</c>. /// </param> /// <returns>The result of the call, if any.</returns> JsNativeFunction = function(callee: JsValueRef; isConstructCall: bool; arguments: PJsValueRef; argumentCount: Word; callbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A promise continuation callback. /// </summary> /// <remarks> /// The host can specify a promise continuation callback in <c>JsSetPromiseContinuationCallback</c>. If /// a script creates a task to be run later, then the promise continuation callback will be called with /// the task and the task should be put in a FIFO queue, to be run when the current script is /// done executing. /// </remarks> /// <param name="task">The task, represented as a JavaScript function.</param> /// <param name="callbackState">The data argument to be passed to the callback.</param> JsPromiseContinuationCallback = procedure(task: JsValueRef; callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new runtime. /// </summary> /// <param name="attributes">The attributes of the runtime to be created.</param> /// <param name="threadService">The thread service for the runtime. Can be null.</param> /// <param name="runtime">The runtime created.</param> /// <remarks>In the edge-mode binary, chakra.dll, this function lacks the <c>runtimeVersion</c> /// parameter (compare to jsrt9.h).</remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateRuntime( attributes: JsRuntimeAttributes; threadService: JsThreadServiceCallback; out runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Performs a full garbage collection. /// </summary> /// <param name="runtime">The runtime in which the garbage collection will be performed.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCollectGarbage( runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Disposes a runtime. /// </summary> /// <remarks> /// Once a runtime has been disposed, all resources owned by it are invalid and cannot be used. /// If the runtime is active (i.e. it is set to be current on a particular thread), it cannot /// be disposed. /// </remarks> /// <param name="runtime">The runtime to dispose.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDisposeRuntime( runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the current memory usage for a runtime. /// </summary> /// <remarks> /// Memory usage can be always be retrieved, regardless of whether or not the runtime is active /// on another thread. /// </remarks> /// <param name="runtime">The runtime whose memory usage is to be retrieved.</param> /// <param name="memoryUsage">The runtime's current memory usage, in bytes.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetRuntimeMemoryUsage( runtime: JsRuntimeHandle; out memoryUsage: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the current memory limit for a runtime. /// </summary> /// <remarks> /// The memory limit of a runtime can be always be retrieved, regardless of whether or not the /// runtime is active on another thread. /// </remarks> /// <param name="runtime">The runtime whose memory limit is to be retrieved.</param> /// <param name="memoryLimit"> /// The runtime's current memory limit, in bytes, or -1 if no limit has been set. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetRuntimeMemoryLimit( runtime: JsRuntimeHandle; out memoryLimit: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the current memory limit for a runtime. /// </summary> /// <remarks> /// <para> /// A memory limit will cause any operation which exceeds the limit to fail with an "out of /// memory" error. Setting a runtime's memory limit to -1 means that the runtime has no memory /// limit. New runtimes default to having no memory limit. If the new memory limit exceeds /// current usage, the call will succeed and any future allocations in this runtime will fail /// until the runtime's memory usage drops below the limit. /// </para> /// <para> /// A runtime's memory limit can be always be set, regardless of whether or not the runtime is /// active on another thread. /// </para> /// </remarks> /// <param name="runtime">The runtime whose memory limit is to be set.</param> /// <param name="memoryLimit"> /// The new runtime memory limit, in bytes, or -1 for no memory limit. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetRuntimeMemoryLimit( runtime: JsRuntimeHandle; memoryLimit: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets a memory allocation callback for specified runtime /// </summary> /// <remarks> /// <para> /// Registering a memory allocation callback will cause the runtime to call back to the host /// whenever it acquires memory from, or releases memory to, the OS. The callback routine is /// called before the runtime memory manager allocates a block of memory. The allocation will /// be rejected if the callback returns false. The runtime memory manager will also invoke the /// callback routine after freeing a block of memory, as well as after allocation failures. /// </para> /// <para> /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// </para> /// <para> /// The return value of the callback is not stored; previously rejected allocations will not /// prevent the runtime from invoking the callback again later for new memory allocations. /// </para> /// </remarks> /// <param name="runtime">The runtime for which to register the allocation callback.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="allocationCallback"> /// Memory allocation callback to be called for memory allocation events. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetRuntimeMemoryAllocationCallback( runtime: JsRuntimeHandle; callbackState: Pointer; allocationCallback: JsMemoryAllocationCallback): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets a callback function that is called by the runtime before garbage collection. /// </summary> /// <remarks> /// <para> /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// </para> /// <para> /// The callback can be used by hosts to prepare for garbage collection. For example, by /// releasing unnecessary references on Chakra objects. /// </para> /// </remarks> /// <param name="runtime">The runtime for which to register the allocation callback.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="beforeCollectCallback">The callback function being set.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetRuntimeBeforeCollectCallback( runtime: JsRuntimeHandle; callbackState: Pointer; beforeCollectCallback: JsBeforeCollectCallback): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Adds a reference to a garbage collected object. /// </summary> /// <remarks> /// This only needs to be called on <c>JsRef</c> handles that are not going to be stored /// somewhere on the stack. Calling <c>JsAddRef</c> ensures that the object the <c>JsRef</c> /// refers to will not be freed until <c>JsRelease</c> is called. /// </remarks> /// <param name="ref">The object to add a reference to.</param> /// <param name="count">The object's new reference count (can pass in null).</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsAddRef( ref: JsRef; count: PCardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Releases a reference to a garbage collected object. /// </summary> /// <remarks> /// Removes a reference to a <c>JsRef</c> handle that was created by <c>JsAddRef</c>. /// </remarks> /// <param name="ref">The object to add a reference to.</param> /// <param name="count">The object's new reference count (can pass in null).</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsRelease( ref: JsRef; count: PCardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets a callback function that is called by the runtime before garbage collection of /// an object. /// </summary> /// <remarks> /// <para> /// The callback is invoked on the current runtime execution thread, therefore execution is /// blocked until the callback completes. /// </para> /// </remarks> /// <param name="ref">The object for which to register the callback.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="objectBeforeCollectCallback">The callback function being set. Use null to clear /// previously registered callback.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetObjectBeforeCollectCallback( ref: JsRef; callbackState: Pointer; objectBeforeCollectCallback: JsObjectBeforeCollectCallback): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a script context for running scripts. /// </summary> /// <remarks> /// Each script context has its own global object that is isolated from all other script /// contexts. /// </remarks> /// <param name="runtime">The runtime the script context is being created in.</param> /// <param name="newContext">The created script context.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateContext( runtime: JsRuntimeHandle; out newContext: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the current script context on the thread. /// </summary> /// <param name="currentContext"> /// The current script context on the thread, null if there is no current script context. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetCurrentContext( out currentContext: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the current script context on the thread. /// </summary> /// <param name="context">The script context to make current.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetCurrentContext( context: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the script context that the object belongs to. /// </summary> /// <param name="object">The object to get the context from.</param> /// <param name="context">The context the object belongs to.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetContextOfObject( _object: JsValueRef; out context: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the internal data set on JsrtContext. /// </summary> /// <param name="context">The context to get the data from.</param> /// <param name="data">The pointer to the data where data will be returned.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetContextData( context: JsContextRef; out data: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the internal data of JsrtContext. /// </summary> /// <param name="context">The context to set the data to.</param> /// <param name="data">The pointer to the data to be set.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetContextData( context: JsContextRef; data: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the runtime that the context belongs to. /// </summary> /// <param name="context">The context to get the runtime from.</param> /// <param name="runtime">The runtime the context belongs to.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetRuntime( context: JsContextRef; out runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Tells the runtime to do any idle processing it need to do. /// </summary> /// <remarks> /// <para> /// If idle processing has been enabled for the current runtime, calling <c>JsIdle</c> will /// inform the current runtime that the host is idle and that the runtime can perform /// memory cleanup tasks. /// </para> /// <para> /// <c>JsIdle</c> can also return the number of system ticks until there will be more idle work /// for the runtime to do. Calling <c>JsIdle</c> before this number of ticks has passed will do /// no work. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="nextIdleTick"> /// The next system tick when there will be more idle work to do. Can be null. Returns the /// maximum number of ticks if there no upcoming idle work to do. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsIdle( nextIdleTick: PCardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the symbol associated with the property ID. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="propertyId">The property ID to get the symbol of.</param> /// <param name="symbol">The symbol associated with the property ID.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetSymbolFromPropertyId( propertyId: JsPropertyIdRef; out symbol: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the type of property /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="propertyId">The property ID to get the type of.</param> /// <param name="propertyIdType">The JsPropertyIdType of the given property ID</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetPropertyIdType( propertyId: JsPropertyIdRef; out propertyIdType: JsPropertyIdType): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the property ID associated with the symbol. /// </summary> /// <remarks> /// <para> /// Property IDs are specific to a context and cannot be used across contexts. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="symbol"> /// The symbol whose property ID is being retrieved. /// </param> /// <param name="propertyId">The property ID for the given symbol.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetPropertyIdFromSymbol( symbol: JsValueRef; out propertyId: JsPropertyIdRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript symbol. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="description">The string description of the symbol. Can be null.</param> /// <param name="result">The new symbol.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateSymbol( description: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the list of all symbol properties on the object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object from which to get the property symbols.</param> /// <param name="propertySymbols">An array of property symbols.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetOwnPropertySymbols( _object: JsValueRef; out propertySymbols: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the value of <c>undefined</c> in the current script context. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="undefinedValue">The <c>undefined</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetUndefinedValue( out undefinedValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the value of <c>null</c> in the current script context. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="nullValue">The <c>null</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetNullValue( out nullValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the value of <c>true</c> in the current script context. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="trueValue">The <c>true</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetTrueValue( out trueValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the value of <c>false</c> in the current script context. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="falseValue">The <c>false</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetFalseValue( out falseValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Boolean value from a <c>bool</c> value. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="value">The value to be converted.</param> /// <param name="booleanValue">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsBoolToBoolean( value: bool; out booleanValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieves the <c>bool</c> value of a Boolean value. /// </summary> /// <param name="value">The value to be converted.</param> /// <param name="boolValue">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsBooleanToBool( value: JsValueRef; out boolValue: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Converts the value to Boolean using standard JavaScript semantics. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="value">The value to be converted.</param> /// <param name="booleanValue">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsConvertValueToBoolean( value: JsValueRef; out booleanValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the JavaScript type of a JsValueRef. /// </summary> /// <param name="value">The value whose type is to be returned.</param> /// <param name="type">The type of the value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetValueType( value: JsValueRef; out _type: JsValueType): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a number value from a <c>double</c> value. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="doubleValue">The <c>double</c> to convert to a number value.</param> /// <param name="value">The new number value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDoubleToNumber( doubleValue: Double; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a number value from an <c>int</c> value. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="intValue">The <c>int</c> to convert to a number value.</param> /// <param name="value">The new number value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsIntToNumber( intValue: Integer; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieves the <c>double</c> value of a number value. /// </summary> /// <remarks> /// This function retrieves the value of a number value. It will fail with /// <c>JsErrorInvalidArgument</c> if the type of the value is not number. /// </remarks> /// <param name="value">The number value to convert to a <c>double</c> value.</param> /// <param name="doubleValue">The <c>double</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsNumberToDouble( value: JsValueRef; out doubleValue: Double): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieves the <c>int</c> value of a number value. /// </summary> /// <remarks> /// This function retrieves the value of a number value and converts to an <c>int</c> value. /// It will fail with <c>JsErrorInvalidArgument</c> if the type of the value is not number. /// </remarks> /// <param name="value">The number value to convert to an <c>int</c> value.</param> /// <param name="intValue">The <c>int</c> value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsNumberToInt( value: JsValueRef; out intValue: Integer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Converts the value to number using standard JavaScript semantics. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="value">The value to be converted.</param> /// <param name="numberValue">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsConvertValueToNumber( value: JsValueRef; out numberValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the length of a string value. /// </summary> /// <param name="stringValue">The string value to get the length of.</param> /// <param name="length">The length of the string.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetStringLength( stringValue: JsValueRef; out length: Integer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Converts the value to string using standard JavaScript semantics. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="value">The value to be converted.</param> /// <param name="stringValue">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsConvertValueToString( value: JsValueRef; out stringValue: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the global object in the current script context. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="globalObject">The global object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetGlobalObject( out globalObject: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The new object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateObject( out _object: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new object that stores some external data. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="data">External data that the object will represent. May be null.</param> /// <param name="finalizeCallback"> /// A callback for when the object is finalized. May be null. /// </param> /// <param name="object">The new object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateExternalObject( data: Pointer; finalizeCallback: JsFinalizeCallback; out _object: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Converts the value to object using standard JavaScript semantics. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="value">The value to be converted.</param> /// <param name="object">The converted value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsConvertValueToObject( value: JsValueRef; out _object: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Returns the prototype of an object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object whose prototype is to be returned.</param> /// <param name="prototypeObject">The object's prototype.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetPrototype( _object: JsValueRef; out prototypeObject: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the prototype of an object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object whose prototype is to be changed.</param> /// <param name="prototypeObject">The object's new prototype.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetPrototype( _object: JsValueRef; prototypeObject: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Performs JavaScript "instanceof" operator test. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to test.</param> /// <param name="constructor">The constructor function to test against.</param> /// <param name="result">Whether "object instanceof constructor" is true.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsInstanceOf( _object: JsValueRef; constr: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Returns a value that indicates whether an object is extensible or not. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to test.</param> /// <param name="value">Whether the object is extensible or not.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetExtensionAllowed( _object: JsValueRef; out value: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Makes an object non-extensible. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to make non-extensible.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsPreventExtension( _object: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="value">The value of the property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetProperty( _object: JsValueRef; propertyId: JsPropertyIdRef; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets a property descriptor for an object's own property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that has the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="propertyDescriptor">The property descriptor.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetOwnPropertyDescriptor( _object: JsValueRef; propertyId: JsPropertyIdRef; out propertyDescriptor: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the list of all properties on the object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object from which to get the property names.</param> /// <param name="propertyNames">An array of property names.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetOwnPropertyNames( _object: JsValueRef; out propertyNames: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Puts an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="value">The new value of the property.</param> /// <param name="useStrictRules">The property set should follow strict mode rules.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetProperty( _object: JsValueRef; propertyId: JsPropertyIdRef; value: JsValueRef; useStrictRules: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object has a property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that may contain the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="hasProperty">Whether the object (or a prototype) has the property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasProperty( _object: JsValueRef; propertyId: JsPropertyIdRef; out hasProperty: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Deletes an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="useStrictRules">The property set should follow strict mode rules.</param> /// <param name="result">Whether the property was deleted.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDeleteProperty( _object: JsValueRef; propertyId: JsPropertyIdRef; useStrictRules: bool; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Defines a new object's own property from a property descriptor. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that has the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="propertyDescriptor">The property descriptor.</param> /// <param name="result">Whether the property was defined.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDefineProperty( _object: JsValueRef; propertyId: JsPropertyIdRef; propertyDescriptor: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Tests whether an object has a value at the specified index. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to operate on.</param> /// <param name="index">The index to test.</param> /// <param name="result">Whether the object has a value at the specified index.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasIndexedProperty( _object: JsValueRef; index: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieve the value at the specified index of an object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to operate on.</param> /// <param name="index">The index to retrieve.</param> /// <param name="result">The retrieved value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetIndexedProperty( _object: JsValueRef; index: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Set the value at the specified index of an object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to operate on.</param> /// <param name="index">The index to set.</param> /// <param name="value">The value to set.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetIndexedProperty( _object: JsValueRef; index: JsValueRef; value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Delete the value at the specified index of an object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to operate on.</param> /// <param name="index">The index to delete.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDeleteIndexedProperty( _object: JsValueRef; index: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object has its indexed properties in external data. /// </summary> /// <param name="object">The object.</param> /// <param name="value">Whether the object has its indexed properties in external data.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasIndexedPropertiesExternalData( _object: JsValueRef; out value: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieves an object's indexed properties external data information. /// </summary> /// <param name="object">The object.</param> /// <param name="data">The external data back store for the object's indexed properties.</param> /// <param name="arrayType">The array element type in external data.</param> /// <param name="elementLength">The number of array elements in external data.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetIndexedPropertiesExternalData( _object: JsValueRef; out data: Pointer; out arrayType: JsTypedArrayType; out elementLength: Cardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets an object's indexed properties to external data. The external data will be used as back /// store for the object's indexed properties and accessed like a typed array. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object to operate on.</param> /// <param name="data">The external data to be used as back store for the object's indexed properties.</param> /// <param name="arrayType">The array element type in external data.</param> /// <param name="elementLength">The number of array elements in external data.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetIndexedPropertiesToExternalData( _object: JsValueRef; data: Pointer; arrayType: JsTypedArrayType; elementLength: Cardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Compare two JavaScript values for equality. /// </summary> /// <remarks> /// <para> /// This function is equivalent to the <c>==</c> operator in Javascript. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="object1">The first object to compare.</param> /// <param name="object2">The second object to compare.</param> /// <param name="result">Whether the values are equal.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsEquals( object1: JsValueRef; object2: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Compare two JavaScript values for strict equality. /// </summary> /// <remarks> /// <para> /// This function is equivalent to the <c>===</c> operator in Javascript. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="object1">The first object to compare.</param> /// <param name="object2">The second object to compare.</param> /// <param name="result">Whether the values are strictly equal.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsStrictEquals( object1: JsValueRef; object2: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object is an external object. /// </summary> /// <param name="object">The object.</param> /// <param name="value">Whether the object is an external object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasExternalData( _object: JsValueRef; out value: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieves the data from an external object. /// </summary> /// <param name="object">The external object.</param> /// <param name="externalData"> /// The external data stored in the object. Can be null if no external data is stored in the /// object. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetExternalData( _object: JsValueRef; out externalData: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the external data on an external object. /// </summary> /// <param name="object">The external object.</param> /// <param name="externalData"> /// The external data to be stored in the object. Can be null if no external data is /// to be stored in the object. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetExternalData( _object: JsValueRef; externalData: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript array object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="length">The initial length of the array.</param> /// <param name="result">The new array object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateArray( length: Cardinal; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript ArrayBuffer object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="byteLength"> /// The number of bytes in the ArrayBuffer. /// </param> /// <param name="result">The new ArrayBuffer object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateArrayBuffer( byteLength: Cardinal; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript ArrayBuffer object to access external memory. /// </summary> /// <remarks>Requires an active script context.</remarks> /// <param name="data">A pointer to the external memory.</param> /// <param name="byteLength">The number of bytes in the external memory.</param> /// <param name="finalizeCallback">A callback for when the object is finalized. May be null.</param> /// <param name="callbackState">User provided state that will be passed back to finalizeCallback.</param> /// <param name="result">The new ArrayBuffer object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateExternalArrayBuffer( data: Pointer; byteLength: Cardinal; finalizeCallback: JsFinalizeCallback; callbackState: Pointer; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript typed array object. /// </summary> /// <remarks> /// <para> /// The <c>baseArray</c> can be an <c>ArrayBuffer</c>, another typed array, or a JavaScript /// <c>Array</c>. The returned typed array will use the baseArray if it is an ArrayBuffer, or /// otherwise create and use a copy of the underlying source array. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="arrayType">The type of the array to create.</param> /// <param name="baseArray"> /// The base array of the new array. Use <c>JS_INVALID_REFERENCE</c> if no base array. /// </param> /// <param name="byteOffset"> /// The offset in bytes from the start of baseArray (ArrayBuffer) for result typed array to reference. /// Only applicable when baseArray is an ArrayBuffer object. Must be 0 otherwise. /// </param> /// <param name="elementLength"> /// The number of elements in the array. Only applicable when creating a new typed array without /// baseArray (baseArray is <c>JS_INVALID_REFERENCE</c>) or when baseArray is an ArrayBuffer object. /// Must be 0 otherwise. /// </param> /// <param name="result">The new typed array object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateTypedArray( arrayType: JsTypedArrayType; baseArray: JsValueRef; byteOffset: Cardinal; elementLength: Cardinal; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript DataView object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="arrayBuffer"> /// An existing ArrayBuffer object to use as the storage for the result DataView object. /// </param> /// <param name="byteOffset"> /// The offset in bytes from the start of arrayBuffer for result DataView to reference. /// </param> /// <param name="byteLength"> /// The number of bytes in the ArrayBuffer for result DataView to reference. /// </param> /// <param name="result">The new DataView object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateDataView( arrayBuffer: JsValueRef; byteOffset: Cardinal; byteLength: Cardinal; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Obtains frequently used properties of a typed array. /// </summary> /// <param name="typedArray">The typed array instance.</param> /// <param name="arrayType">The type of the array.</param> /// <param name="arrayBuffer">The ArrayBuffer backstore of the array.</param> /// <param name="byteOffset">The offset in bytes from the start of arrayBuffer referenced by the array.</param> /// <param name="byteLength">The number of bytes in the array.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetTypedArrayInfo( typedArray: JsValueRef; arrayType: PJsTypedArrayType; arrayBuffer: PJsValueRef; byteOffset: PCardinal; byteLength: PCardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Obtains the underlying memory storage used by an <c>ArrayBuffer</c>. /// </summary> /// <param name="arrayBuffer">The ArrayBuffer instance.</param> /// <param name="buffer"> /// The ArrayBuffer's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the ArrayBuffer. The buffer pointer does not count as a reference to the ArrayBuffer for the purpose /// of garbage collection. /// </param> /// <param name="bufferLength">The number of bytes in the buffer.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetArrayBufferStorage( arrayBuffer: JsValueRef; out buffer: ChakraBytePtr; out bufferLength: Cardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Obtains the underlying memory storage used by a typed array. /// </summary> /// <param name="typedArray">The typed array instance.</param> /// <param name="buffer"> /// The array's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the array. The buffer pointer does not count as a reference to the array for the purpose /// of garbage collection. /// </param> /// <param name="bufferLength">The number of bytes in the buffer.</param> /// <param name="arrayType">The type of the array.</param> /// <param name="elementSize"> /// The size of an element of the array. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetTypedArrayStorage( typedArray: JsValueRef; out buffer: ChakraBytePtr; out bufferLength: Cardinal; out arrayType: JsTypedArrayType; out elementSize: Integer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Obtains the underlying memory storage used by a DataView. /// </summary> /// <param name="dataView">The DataView instance.</param> /// <param name="buffer"> /// The DataView's buffer. The lifetime of the buffer returned is the same as the lifetime of the /// the DataView. The buffer pointer does not count as a reference to the DataView for the purpose /// of garbage collection. /// </param> /// <param name="bufferLength">The number of bytes in the buffer.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetDataViewStorage( dataView: JsValueRef; out buffer: ChakraBytePtr; out bufferLength: Cardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Invokes a function. /// </summary> /// <remarks> /// Requires thisArg as first argument of arguments. /// Requires an active script context. /// </remarks> /// <param name="function">The function to invoke.</param> /// <param name="arguments">The arguments to the call.</param> /// <param name="argumentCount">The number of arguments being passed in to the function.</param> /// <param name="result">The value returned from the function invocation, if any.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCallFunction( _function: JsValueRef; arguments: PJsValueRef; argumentCount: Word; result: PJsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Invokes a function as a constructor. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="function">The function to invoke as a constructor.</param> /// <param name="arguments">The arguments to the call.</param> /// <param name="argumentCount">The number of arguments being passed in to the function.</param> /// <param name="result">The value returned from the function invocation.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsConstructObject( _function: JsValueRef; arguments: PJsValueRef; argumentCount: Word; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript function. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="nativeFunction">The method to call when the function is invoked.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="function">The new function object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateFunction( nativeFunction: JsNativeFunction; callbackState: Pointer; out _function: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript function with name. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="name">The name of this function that will be used for diagnostics and stringification purposes.</param> /// <param name="nativeFunction">The method to call when the function is invoked.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="function">The new function object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateNamedFunction( name: JsValueRef; nativeFunction: JsNativeFunction; callbackState: Pointer; out _function: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript RangeError error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateRangeError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript ReferenceError error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateReferenceError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript SyntaxError error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateSyntaxError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript TypeError error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateTypeError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript URIError error object /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="message">Message for the error object.</param> /// <param name="error">The new error object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateURIError( _message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether the runtime of the current context is in an exception state. /// </summary> /// <remarks> /// <para> /// If a call into the runtime results in an exception (either as the result of running a /// script or due to something like a conversion failure), the runtime is placed into an /// "exception state." All calls into any context created by the runtime (except for the /// exception APIs) will fail with <c>JsErrorInExceptionState</c> until the exception is /// cleared. /// </para> /// <para> /// If the runtime of the current context is in the exception state when a callback returns /// into the engine, the engine will automatically rethrow the exception. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="hasException"> /// Whether the runtime of the current context is in the exception state. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasException( out hasException: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Returns the exception that caused the runtime of the current context to be in the /// exception state and resets the exception state for that runtime. /// </summary> /// <remarks> /// <para> /// If the runtime of the current context is not in an exception state, this API will return /// <c>JsErrorInvalidArgument</c>. If the runtime is disabled, this will return an exception /// indicating that the script was terminated, but it will not clear the exception (the /// exception will be cleared if the runtime is re-enabled using /// <c>JsEnableRuntimeExecution</c>). /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="exception">The exception for the runtime of the current context.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetAndClearException( out exception: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the runtime of the current context to an exception state. /// </summary> /// <remarks> /// <para> /// If the runtime of the current context is already in an exception state, this API will /// return <c>JsErrorInExceptionState</c>. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="exception"> /// The JavaScript exception to set for the runtime of the current context. /// </param> /// <returns> /// JsNoError if the engine was set into an exception state, a failure code otherwise. /// </returns> function JsSetException( exception: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Suspends script execution and terminates any running scripts in a runtime. /// </summary> /// <remarks> /// <para> /// Calls to a suspended runtime will fail until <c>JsEnableRuntimeExecution</c> is called. /// </para> /// <para> /// This API does not have to be called on the thread the runtime is active on. Although the /// runtime will be set into a suspended state, an executing script may not be suspended /// immediately; a running script will be terminated with an uncatchable exception as soon as /// possible. /// </para> /// <para> /// Suspending execution in a runtime that is already suspended is a no-op. /// </para> /// </remarks> /// <param name="runtime">The runtime to be suspended.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsDisableRuntimeExecution( runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Enables script execution in a runtime. /// </summary> /// <remarks> /// Enabling script execution in a runtime that already has script execution enabled is a /// no-op. /// </remarks> /// <param name="runtime">The runtime to be enabled.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsEnableRuntimeExecution( runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Returns a value that indicates whether script execution is disabled in the runtime. /// </summary> /// <param name="runtime">Specifies the runtime to check if execution is disabled.</param> /// <param name="isDisabled">If execution is disabled, <c>true</c>, <c>false</c> otherwise.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsIsRuntimeExecutionDisabled( runtime: JsRuntimeHandle; out isDisabled: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets a promise continuation callback function that is called by the context when a task /// needs to be queued for future execution /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="promiseContinuationCallback">The callback function being set.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetPromiseContinuationCallback( promiseContinuationCallback: JsPromiseContinuationCallback; callbackState: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} implementation {$ifdef MSWINDOWS} const chakracore = 'chakracore.dll'; {$endif} {$ifdef DARWIN} const chakracore = 'libChakraCore.dylib'; {$endif} {$ifdef LINUX} const chakracore = 'libChakraCore.so'; {$endif} function JsCreateRuntime; external chakracore; function JsCollectGarbage; external chakracore; function JsDisposeRuntime; external chakracore; function JsGetRuntimeMemoryUsage; external chakracore; function JsGetRuntimeMemoryLimit; external chakracore; function JsSetRuntimeMemoryLimit; external chakracore; function JsSetRuntimeMemoryAllocationCallback; external chakracore; function JsSetRuntimeBeforeCollectCallback; external chakracore; function JsAddRef; external chakracore; function JsRelease; external chakracore; function JsSetObjectBeforeCollectCallback; external chakracore; function JsCreateContext; external chakracore; function JsGetCurrentContext; external chakracore; function JsSetCurrentContext; external chakracore; function JsGetContextOfObject; external chakracore; function JsGetContextData; external chakracore; function JsSetContextData; external chakracore; function JsGetRuntime; external chakracore; function JsIdle; external chakracore; function JsGetSymbolFromPropertyId; external chakracore; function JsGetPropertyIdType; external chakracore; function JsGetPropertyIdFromSymbol; external chakracore; function JsCreateSymbol; external chakracore; function JsGetOwnPropertySymbols; external chakracore; function JsGetUndefinedValue; external chakracore; function JsGetNullValue; external chakracore; function JsGetTrueValue; external chakracore; function JsGetFalseValue; external chakracore; function JsBoolToBoolean; external chakracore; function JsBooleanToBool; external chakracore; function JsConvertValueToBoolean; external chakracore; function JsGetValueType; external chakracore; function JsDoubleToNumber; external chakracore; function JsIntToNumber; external chakracore; function JsNumberToDouble; external chakracore; function JsNumberToInt; external chakracore; function JsConvertValueToNumber; external chakracore; function JsGetStringLength; external chakracore; function JsConvertValueToString; external chakracore; function JsGetGlobalObject; external chakracore; function JsCreateObject; external chakracore; function JsCreateExternalObject; external chakracore; function JsConvertValueToObject; external chakracore; function JsGetPrototype; external chakracore; function JsSetPrototype; external chakracore; function JsInstanceOf; external chakracore; function JsGetExtensionAllowed; external chakracore; function JsPreventExtension; external chakracore; function JsGetProperty; external chakracore; function JsGetOwnPropertyDescriptor; external chakracore; function JsGetOwnPropertyNames; external chakracore; function JsSetProperty; external chakracore; function JsHasProperty; external chakracore; function JsDeleteProperty; external chakracore; function JsDefineProperty; external chakracore; function JsHasIndexedProperty; external chakracore; function JsGetIndexedProperty; external chakracore; function JsSetIndexedProperty; external chakracore; function JsDeleteIndexedProperty; external chakracore; function JsHasIndexedPropertiesExternalData; external chakracore; function JsGetIndexedPropertiesExternalData; external chakracore; function JsSetIndexedPropertiesToExternalData; external chakracore; function JsEquals; external chakracore; function JsStrictEquals; external chakracore; function JsHasExternalData; external chakracore; function JsGetExternalData; external chakracore; function JsSetExternalData; external chakracore; function JsCreateArray; external chakracore; function JsCreateArrayBuffer; external chakracore; function JsCreateExternalArrayBuffer; external chakracore; function JsCreateTypedArray; external chakracore; function JsCreateDataView; external chakracore; function JsGetTypedArrayInfo; external chakracore; function JsGetArrayBufferStorage; external chakracore; function JsGetTypedArrayStorage; external chakracore; function JsGetDataViewStorage; external chakracore; function JsCallFunction; external chakracore; function JsConstructObject; external chakracore; function JsCreateFunction; external chakracore; function JsCreateNamedFunction; external chakracore; function JsCreateError; external chakracore; function JsCreateRangeError; external chakracore; function JsCreateReferenceError; external chakracore; function JsCreateSyntaxError; external chakracore; function JsCreateTypeError; external chakracore; function JsCreateURIError; external chakracore; function JsHasException; external chakracore; function JsGetAndClearException; external chakracore; function JsSetException; external chakracore; function JsDisableRuntimeExecution; external chakracore; function JsEnableRuntimeExecution; external chakracore; function JsIsRuntimeExecutionDisabled; external chakracore; function JsSetPromiseContinuationCallback; external chakracore; end. ================================================ FILE: src/ChakraCore.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to host Chakra. /// /// \file /// \brief The Chakra Core hosting API. /// /// This file contains a flat C API layer. This is the API exported by ChakraCore.dll. unit ChakraCore; {$include common.inc} {$minenumsize 4} interface uses Compat, ChakraCommon; type /// <summary> /// A reference to an ES module. /// </summary> /// <remarks> /// A module record represents an ES module. /// </remarks> JsModuleRecord = Pointer; /// <summary> /// A reference to an object owned by the SharedArrayBuffer. /// </summary> /// <remarks> /// This represents SharedContents which is heap allocated object, it can be passed through /// different runtimes to share the underlying buffer. /// </remarks> JsSharedArrayBufferContentHandle = Pointer; /// <summary> /// Flags for parsing a module. /// </summary> JsParseModuleSourceFlags = ( /// <summary> /// Module source is UTF16. /// </summary> JsParseModuleSourceFlags_DataIsUTF16LE = $00000000, /// <summary> /// Module source is UTF8. /// </summary> JsParseModuleSourceFlags_DataIsUTF8 = $00000001 ); /// <summary> /// The types of host info that can be set on a module record with JsSetModuleHostInfo. /// </summary> /// <remarks> /// For more information see JsSetModuleHostInfo. /// </remarks> JsModuleHostInfoKind = ( /// <summary> /// An exception object - e.g. if the module file cannot be found. /// </summary> JsModuleHostInfo_Exception = $01, /// <summary> /// Host defined info. /// </summary> JsModuleHostInfo_HostDefined = $02, /// <summary> /// Callback for receiving notification when module is ready. /// </summary> JsModuleHostInfo_NotifyModuleReadyCallback = $03, /// <summary> /// Callback for receiving notification to fetch a dependent module. /// </summary> JsModuleHostInfo_FetchImportedModuleCallback = $04, /// <summary> /// Callback for receiving notification for calls to ```import()``` /// </summary> JsModuleHostInfo_FetchImportedModuleFromScriptCallback = $05, /// <summary> /// URL for use in error stack traces and debugging. /// </summary> JsModuleHostInfo_Url = $06 ); /// <summary> /// The possible states for a Promise object. /// </summary> JsPromiseState = ( JsPromiseStatePending = $0, JsPromiseStateFulfilled = $1, JsPromiseStateRejected = $2 ); /// <summary> /// User implemented callback to fetch additional imported modules in ES modules. /// </summary> /// <remarks> /// The callback is invoked on the current runtime execution thread, therefore execution is blocked until /// the callback completes. Notify the host to fetch the dependent module. This is the "import" part /// before HostResolveImportedModule in ES6 spec. This notifies the host that the referencing module has /// the specified module dependency, and the host needs to retrieve the module back. /// /// Callback should: /// 1. Check if the requested module has been requested before - if yes return the existing /// module record /// 2. If no create and initialize a new module record with JsInitializeModuleRecord to /// return and schedule a call to JsParseModuleSource for the new record. /// </remarks> /// <param name="referencingModule">The referencing module that is requesting the dependent module.</param> /// <param name="specifier">The specifier coming from the module source code.</param> /// <param name="dependentModuleRecord">The ModuleRecord of the dependent module. If the module was requested /// before from other source, return the existing ModuleRecord, otherwise /// return a newly created ModuleRecord.</param> /// <returns> /// Returns a <c>JsNoError</c> if the operation succeeded an error code otherwise. /// </returns> FetchImportedModuleCallBack = function(referencingModule: JsModuleRecord; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// User implemented callback to fetch imported modules dynamically in scripts. /// </summary> /// <remarks> /// The callback is invoked on the current runtime execution thread, therefore execution is blocked untill /// the callback completes. Notify the host to fetch the dependent module. This is used for the dynamic /// import() syntax. /// /// Callback should: /// 1. Check if the requested module has been requested before - if yes return the existing module record /// 2. If no create and initialize a new module record with JsInitializeModuleRecord to return and /// schedule a call to JsParseModuleSource for the new record. /// </remarks> /// <param name="dwReferencingSourceContext">The referencing script context that calls import()</param> /// <param name="specifier">The specifier provided to the import() call.</param> /// <param name="dependentModuleRecord">The ModuleRecord of the dependent module. If the module was requested /// before from other source, return the existing ModuleRecord, otherwise /// return a newly created ModuleRecord.</param> /// <returns> /// Returns <c>JsNoError</c> if the operation succeeded or an error code otherwise. /// </returns> FetchImportedModuleFromScriptCallBack = function(dwReferencingSourceContext: JsSourceContext; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// User implemented callback to get notification when the module is ready. /// </summary> /// <remarks> /// The callback is invoked on the current runtime execution thread, therefore execution is blocked until the /// callback completes. This callback should schedule a call to JsEvaluateModule to run the module that has been loaded. /// </remarks> /// <param name="referencingModule">The referencing module that has finished running ModuleDeclarationInstantiation step.</param> /// <param name="exceptionVar">If nullptr, the module is successfully initialized and host should queue the execution job /// otherwise it's the exception object.</param> /// <returns> /// Returns a JsErrorCode - note, the return value is ignored. /// </returns> NotifyModuleReadyCallback = function(referencingModule: JsModuleRecord; exceptionVar: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A structure containing information about a native function callback. /// </summary> PJsNativeFunctionInfo = ^JsNativeFunctionInfo; JsNativeFunctionInfo = record thisArg: JsValueRef; newTargetArg: JsValueRef; isConstructCall: bool; end; /// <summary> /// A function callback. /// </summary> /// <param name="callee"> /// A function object that represents the function being invoked. /// </param> /// <param name="arguments">The arguments to the call.</param> /// <param name="argumentCount">The number of arguments.</param> /// <param name="info">Additional information about this function call.</param> /// <param name="callbackState"> /// The state passed to <c>JsCreateFunction</c>. /// </param> /// <returns>The result of the call, if any.</returns> JsEnhancedNativeFunction = function(callee: JsValueRef; arguments: PJsValueRef; argumentCount: Word; info: PJsNativeFunctionInfo; callbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// A Promise Rejection Tracker callback. /// </summary> /// <remarks> /// The host can specify a promise rejection tracker callback in <c>JsSetHostPromiseRejectionTracker</c>. /// If a promise is rejected with no reactions or a reaction is added to a promise that was rejected /// before it had reactions by default nothing is done. /// A Promise Rejection Tracker callback may be set - which will then be called when this occurs. /// Note - per draft ECMASpec 2018 25.4.1.9 this function should not set or return an exception /// Note also the promise and reason parameters may be garbage collected after this function is called /// if you wish to make further use of them you will need to use JsAddRef to preserve them /// However if you use JsAddRef you must also call JsRelease and not hold unto them after /// a handled notification (both per spec and to avoid memory leaks) /// </remarks> /// <param name="promise">The promise object, represented as a JsValueRef.</param> /// <param name="reason">The value/cause of the rejection, represented as a JsValueRef.</param> /// <param name="handled">Boolean - false for promiseRejected: i.e. if the promise has just been rejected with no handler, /// true for promiseHandled: i.e. if it was rejected before without a handler and is now being handled.</param> /// <param name="callbackState">The state passed to <c>JsSetHostPromiseRejectionTracker</c>.</param> JsHostPromiseRejectionTrackerCallback = procedure(promise, reason: JsValueRef; handled: bool; callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new enhanced JavaScript function. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="nativeFunction">The method to call when the function is invoked.</param> /// <param name="metadata">If this is not <c>JS_INVALID_REFERENCE</c>, it is converted to a string and used as the name of the function.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <param name="function">The new function object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateEnhancedFunction(nativeFunction: JsEnhancedNativeFunction; metadata: JsValueRef; callbackState: Pointer; out _function: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Initialize a ModuleRecord from host /// </summary> /// <remarks> /// Bootstrap the module loading process by creating a new module record. /// </remarks> /// <param name="referencingModule">The parent module of the new module - nullptr for a root module.</param> /// <param name="normalizedSpecifier">The normalized specifier for the module.</param> /// <param name="moduleRecord">The new module record. The host should not try to call this API twice /// with the same normalizedSpecifier.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsInitializeModuleRecord( referencingModule: JsModuleRecord; normalizedSpecifier: JsValueRef; out moduleRecord: JsModuleRecord): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Parse the source for an ES module /// </summary> /// <remarks> /// This is basically ParseModule operation in ES6 spec. It is slightly different in that: /// a) The ModuleRecord was initialized earlier, and passed in as an argument. /// b) This includes a check to see if the module being Parsed is the last module in the /// dependency tree. If it is it automatically triggers Module Instantiation. /// </remarks> /// <param name="requestModule">The ModuleRecord being parsed.</param> /// <param name="sourceContext">A cookie identifying the script that can be used by debuggable script contexts.</param> /// <param name="script">The source script to be parsed, but not executed in this code.</param> /// <param name="scriptLength">The length of sourceText in bytes. As the input might contain a embedded null.</param> /// <param name="sourceFlag">The type of the source code passed in. It could be utf16 or utf8 at this time.</param> /// <param name="exceptionValueRef">The error object if there is parse error.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsParseModuleSource( requestModule: JsModuleRecord; sourceContext: JsSourceContext; script: PByte; scriptLength: Cardinal; sourceFlag: JsParseModuleSourceFlags; out exceptionValueRef: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Execute module code. /// </summary> /// <remarks> /// This method implements 15.2.1.1.6.5, "ModuleEvaluation" concrete method. /// This method should be called after the engine notifies the host that the module is ready. /// This method only needs to be called on root modules - it will execute all of the dependent modules. /// /// One moduleRecord will be executed only once. Additional execution call on the same moduleRecord will fail. /// </remarks> /// <param name="requestModule">The ModuleRecord being executed.</param> /// <param name="result">The return value of the module.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsModuleEvaluation( requestModule: JsModuleRecord; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Set host info for the specified module. /// </summary> /// <remarks> /// This is used for four things: /// 1. Setting up the callbacks for module loading - note these are actually /// set on the current Context not the module so only have to be set for /// the first root module in any given context. /// 2. Setting host defined info on a module record - can be anything that /// you wish to associate with your modules. /// 3. Setting a URL for a module to be used for stack traces/debugging - /// note this must be set before calling JsParseModuleSource on the module /// or it will be ignored. /// 4. Setting an exception on the module object - only relevant prior to it being Parsed. /// </remarks> /// <param name="requestModule">The request module.</param> /// <param name="moduleHostInfo">The type of host info to be set.</param> /// <param name="hostInfo">The host info to be set.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetModuleHostInfo( requestModule: JsModuleRecord; moduleHostInfo: JsModuleHostInfoKind; hostInfo: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieve the host info for the specified module. /// </summary> /// <remarks> /// This can used to retrieve info previously set with JsSetModuleHostInfo. /// </remarks> /// <param name="requestModule">The request module.</param> /// <param name="moduleHostInfo">The type of host info to be retrieved.</param> /// <param name="hostInfo">The retrieved host info for the module.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetModuleHostInfo( requestModule: JsModuleRecord; moduleHostInfo: JsModuleHostInfoKind; out hostInfo: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Returns metadata relating to the exception that caused the runtime of the current context /// to be in the exception state and resets the exception state for that runtime. The metadata /// includes a reference to the exception itself. /// </summary> /// <remarks> /// <para> /// If the runtime of the current context is not in an exception state, this API will return /// <c>JsErrorInvalidArgument</c>. If the runtime is disabled, this will return an exception /// indicating that the script was terminated, but it will not clear the exception (the /// exception will be cleared if the runtime is re-enabled using /// <c>JsEnableRuntimeExecution</c>). /// </para> /// <para> /// The metadata value is a javascript object with the following properties: <c>exception</c>, the /// thrown exception object; <c>line</c>, the 0 indexed line number where the exception was thrown; /// <c>column</c>, the 0 indexed column number where the exception was thrown; <c>length</c>, the /// source-length of the cause of the exception; <c>source</c>, a string containing the line of /// source code where the exception was thrown; and <c>url</c>, a string containing the name of /// the script file containing the code that threw the exception. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="metadata">The exception metadata for the runtime of the current context.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetAndClearExceptionWithMetadata( out metadata: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} type /// <summary> /// Called by the runtime to load the source code of the serialized script. /// </summary> /// <param name="sourceContext">The context passed to Js[Parse|Run]SerializedScriptCallback</param> /// <param name="script">The script returned.</param> /// <returns> /// true if the operation succeeded, false otherwise. /// </returns> JsSerializedLoadScriptCallback = function( sourceContext: JsSourceContext; out value: JsValueRef; out parseAttributes: JsParseScriptAttributes): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Create JavascriptString variable from ASCII or Utf8 string /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// Input string can be either ASCII or Utf8 /// </para> /// </remarks> /// <param name="content">Pointer to string memory.</param> /// <param name="length">Number of bytes within the string</param> /// <param name="value">JsValueRef representing the JavascriptString</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateString( content: PAnsiChar; length: size_t; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Create JavascriptString variable from Utf16 string /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// Expects Utf16 string /// </para> /// </remarks> /// <param name="content">Pointer to string memory.</param> /// <param name="length">Number of characters within the string</param> /// <param name="value">JsValueRef representing the JavascriptString</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateStringUtf16( content: PUnicodeChar; length: size_t; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Write JavascriptString value into C string buffer (Utf8) /// </summary> /// <remarks> /// <para> /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `length` argument will return the length needed. /// </para> /// </remarks> /// <param name="value">JavascriptString value</param> /// <param name="buffer">Pointer to buffer</param> /// <param name="bufferSize">Buffer size</param> /// <param name="length">Total number of characters needed or written</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCopyString( value: JsValueRef; buffer: PAnsiChar; bufferSize: size_t; length: Psize_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Write string value into Utf16 string buffer /// </summary> /// <remarks> /// <para> /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `written` argument will return the length needed. /// </para> /// <para> /// when start is out of range or < 0, returns JsErrorInvalidArgument /// and `written` will be equal to 0. /// If calculated length is 0 (It can be due to string length or `start` /// and length combination), then `written` will be equal to 0 and call /// returns JsNoError /// </para> /// </remarks> /// <param name="value">JavascriptString value</param> /// <param name="start">start offset of buffer</param> /// <param name="length">length to be written</param> /// <param name="buffer">Pointer to buffer</param> /// <param name="written">Total number of characters written</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCopyStringUtf16( value: JsValueRef; start: Integer; length: Integer; buffer: PUnicodeChar; written: Psize_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Parses a script and returns a function representing the script. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// </para> /// <para> /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// </para> /// </remarks> /// <param name="script">The script to run.</param> /// <param name="sourceContext"> /// A cookie identifying the script that can be used by debuggable script contexts. /// </param> /// <param name="sourceUrl">The location the script came from.</param> /// <param name="parseAttributes">Attribute mask for parsing the script</param> /// <param name="result">The result of the compiled script.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsParse( script: JsValueRef; sourceContext: JsSourceContext; sourceUrl: JsValueRef; parseAttributes: JsParseScriptAttributes; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Executes a script. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// </para> /// <para> /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// </para> /// </remarks> /// <param name="script">The script to run.</param> /// <param name="sourceContext"> /// A cookie identifying the script that can be used by debuggable script contexts. /// </param> /// <param name="sourceUrl">The location the script came from</param> /// <param name="parseAttributes">Attribute mask for parsing the script</param> /// <param name="result">The result of the script, if any. This parameter can be null.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsRun( script: JsValueRef; sourceContext: JsSourceContext; sourceUrl: JsValueRef; parseAttributes: JsParseScriptAttributes; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates the property ID associated with the name. /// </summary> /// <remarks> /// <para> /// Property IDs are specific to a context and cannot be used across contexts. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="name"> /// The name of the property ID to get or create. The name may consist of only digits. /// The string is expected to be ASCII / utf8 encoded. /// </param> /// <param name="length">length of the name in bytes</param> /// <param name="propertyId">The property ID in this runtime for the given name.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreatePropertyId( name: PAnsiChar; length: size_t; out propertyId: JsPropertyIdRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Copies the name associated with the property ID into a buffer. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// `length` argument will return the size needed. /// </para> /// </remarks> /// <param name="propertyId">The property ID to get the name of.</param> /// <param name="buffer">The buffer holding the name associated with the property ID, encoded as utf8</param> /// <param name="bufferSize">Size of the buffer.</param> /// <param name="written">Total number of characters written or to be written</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCopyPropertyId( propertyId: JsPropertyIdRef; buffer: PAnsiChar; bufferSize: size_t; out length: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Serializes a parsed script to a buffer than can be reused. /// </summary> /// <remarks> /// <para> /// <c>JsSerializeScript</c> parses a script and then stores the parsed form of the script in a /// runtime-independent format. The serialized script then can be deserialized in any /// runtime without requiring the script to be re-parsed. /// </para> /// <para> /// Requires an active script context. /// </para> /// <para> /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// </para> /// <para> /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// </para> /// </remarks> /// <param name="script">The script to serialize</param> /// <param name="buffer">ArrayBuffer</param> /// <param name="parseAttributes">Encoding for the script.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSerialize( script: JsValueRef; out buffer: JsValueRef; parseAttributes: JsParseScriptAttributes): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Parses a serialized script and returns a function representing the script. /// Provides the ability to lazy load the script source only if/when it is needed. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="buffer">The serialized script as an ArrayBuffer (preferably ExternalArrayBuffer).</param> /// <param name="scriptLoadCallback"> /// Callback called when the source code of the script needs to be loaded. /// This is an optional parameter, set to null if not needed. /// </param> /// <param name="sourceContext"> /// A cookie identifying the script that can be used by debuggable script contexts. /// This context will passed into scriptLoadCallback. /// </param> /// <param name="sourceUrl">The location the script came from.</param> /// <param name="result">A function representing the script code.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsParseSerialized( buffer: JsValueRef; scriptLoadCallback: JsSerializedLoadScriptCallback; sourceContext: JsSourceContext; sourceUrl: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Runs a serialized script. /// Provides the ability to lazy load the script source only if/when it is needed. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// The runtime will detach the data from the buffer and hold on to it until all /// instances of any functions created from the buffer are garbage collected. /// </para> /// </remarks> /// <param name="buffer">The serialized script as an ArrayBuffer (preferably ExternalArrayBuffer).</param> /// <param name="scriptLoadCallback">Callback called when the source code of the script needs to be loaded.</param> /// <param name="sourceContext"> /// A cookie identifying the script that can be used by debuggable script contexts. /// This context will passed into scriptLoadCallback. /// </param> /// <param name="sourceUrl">The location the script came from.</param> /// <param name="result"> /// The result of running the script, if any. This parameter can be null. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsRunSerialized( buffer: JsValueRef; scriptLoadCallback: JsSerializedLoadScriptCallback; sourceContext: JsSourceContext; sourceUrl: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the state of a given Promise object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="promise">The Promise object.</param> /// <param name="state">The current state of the Promise.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetPromiseState( promise: JsValueRef; out state: JsPromiseState): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the result of a given Promise object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="promise">The Promise object.</param> /// <param name="result">The result of the Promise.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetPromiseResult( promise: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new JavaScript Promise object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="promise">The new Promise object.</param> /// <param name="resolveFunction">The function called to resolve the created Promise object.</param> /// <param name="rejectFunction">The function called to reject the created Promise object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreatePromise( out promise: JsValueRef; out resolveFunction: JsValueRef; out rejectFunction: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} type /// <summary> /// A weak reference to a JavaScript value. /// </summary> /// <remarks> /// A value with only weak references is available for garbage-collection. A strong reference /// to the value (<c>JsValueRef</c>) may be obtained from a weak reference if the value happens /// to still be available. /// </remarks> JsWeakRef = JsRef; /// <summary> /// Creates a weak reference to a value. /// </summary> /// <param name="value">The value to be referenced.</param> /// <param name="weakRef">Weak reference to the value.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateWeakReference( value: JsValueRef; out weakRef: JsWeakRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets a strong reference to the value referred to by a weak reference. /// </summary> /// <param name="weakRef">A weak reference.</param> /// <param name="value">Reference to the value, or <c>JS_INVALID_REFERENCE</c> if the value is /// no longer available.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetWeakReferenceValue( weakRef: JsWeakRef; value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a Javascript SharedArrayBuffer object with shared content get from JsGetSharedArrayBufferContent. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="sharedContents"> /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// </param> /// <param name="result">The new SharedArrayBuffer object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateSharedArrayBufferWithSharedContent( sharedContents: JsSharedArrayBufferContentHandle; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Get the storage object from a SharedArrayBuffer. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="sharedArrayBuffer">The SharedArrayBuffer object.</param> /// <param name="sharedContents"> /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// User should call JsReleaseSharedArrayBufferContentHandle after finished using it. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetSharedArrayBufferContent( sharedArrayBuffer: JsValueRef; out sharedContents: JsSharedArrayBufferContentHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Decrease the reference count on a SharedArrayBuffer storage object. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="sharedContents"> /// The storage object of a SharedArrayBuffer which can be shared between multiple thread. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsReleaseSharedArrayBufferContentHandle( sharedContents: JsSharedArrayBufferContentHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object has a non-inherited property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that may contain the property.</param> /// <param name="propertyId">The ID of the property.</param> /// <param name="hasOwnProperty">Whether the object has the non-inherited property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsHasOwnProperty(_object: JsValueRef; propertyId: JsPropertyIdRef; out hasOwnProperty: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Write JS string value into char string buffer without a null terminator /// </summary> /// <remarks> /// <para> /// When size of the `buffer` is unknown, /// `buffer` argument can be nullptr. /// In that case, `written` argument will return the length needed. /// </para> /// <para> /// When start is out of range or < 0, returns JsErrorInvalidArgument /// and `written` will be equal to 0. /// If calculated length is 0 (It can be due to string length or `start` /// and length combination), then `written` will be equal to 0 and call /// returns JsNoError /// </para> /// <para> /// The JS string `value` will be converted one utf16 code point at a time, /// and if it has code points that do not fit in one byte, those values /// will be truncated. /// </para> /// </remarks> /// <param name="value">JavascriptString value</param> /// <param name="start">Start offset of buffer</param> /// <param name="length">Number of characters to be written</param> /// <param name="buffer">Pointer to buffer</param> /// <param name="written">Total number of characters written</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCopyStringOneByte(value: JsValueRef; start, length: Integer; buffer: PAnsiChar; written: Psize_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Obtains frequently used properties of a data view. /// </summary> /// <param name="dataView">The data view instance.</param> /// <param name="arrayBuffer">The ArrayBuffer backstore of the view.</param> /// <param name="byteOffset">The offset in bytes from the start of arrayBuffer referenced by the array.</param> /// <param name="byteLength">The number of bytes in the array.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetDataViewInfo(dataView: JsValueRef; arrayBuffer: PJsValueRef; byteOffset, byteLength: PCardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determine if one JavaScript value is less than another JavaScript value. /// </summary> /// <remarks> /// <para> /// This function is equivalent to the <c><</c> operator in Javascript. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="object1">The first object to compare.</param> /// <param name="object2">The second object to compare.</param> /// <param name="result">Whether object1 is less than object2.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsLessThan(object1, object2: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determine if one JavaScript value is less than or equal to another JavaScript value. /// </summary> /// <remarks> /// <para> /// This function is equivalent to the <c><=</c> operator in Javascript. /// </para> /// <para> /// Requires an active script context. /// </para> /// </remarks> /// <param name="object1">The first object to compare.</param> /// <param name="object2">The second object to compare.</param> /// <param name="result">Whether object1 is less than or equal to object2.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsLessThanOrEqual(object1, object2: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Creates a new object (with prototype) that stores some external data. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="data">External data that the object will represent. May be null.</param> /// <param name="finalizeCallback"> /// A callback for when the object is finalized. May be null. /// </param> /// <param name="prototype">Prototype object or nullptr.</param> /// <param name="object">The new object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsCreateExternalObjectWithPrototype( data: Pointer; finalizeCallback: JsFinalizeCallback; prototype: JsValueRef; out _object: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="value">The value of the property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectGetProperty(_object, key: JsValueRef; out value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Puts an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="value">The new value of the property.</param> /// <param name="useStrictRules">The property set should follow strict mode rules.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectSetProperty(_object, key, value: JsValueRef; useStrictRules: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object has a property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that may contain the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="hasProperty">Whether the object (or a prototype) has the property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectHasProperty(_object, key: JsValueRef; out hasProperty: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Defines a new object's own property from a property descriptor. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that has the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="propertyDescriptor">The property descriptor.</param> /// <param name="result">Whether the property was defined.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectDefineProperty(_object, key, propertyDescriptor: JsValueRef; out result: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Deletes an object's property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that contains the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="useStrictRules">The property set should follow strict mode rules.</param> /// <param name="result">Whether the property was deleted.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectDeleteProperty(_object, key: JsValueRef; useStrictRules: bool; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets a property descriptor for an object's own property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that has the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="propertyDescriptor">The property descriptor.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectGetOwnPropertyDescriptor(_object, key: JsValueRef; out propertyDescriptor: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines whether an object has a non-inherited property. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="object">The object that may contain the property.</param> /// <param name="key">The key (JavascriptString or JavascriptSymbol) to the property.</param> /// <param name="hasOwnProperty">Whether the object has the non-inherited property.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsObjectHasOwnProperty(_object, key: JsValueRef; out hasOwnProperty: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets whether any action should be taken when a promise is rejected with no reactions /// or a reaction is added to a promise that was rejected before it had reactions. /// By default in either of these cases nothing occurs. /// This function allows you to specify if something should occur and provide a callback /// to implement whatever should occur. /// </summary> /// <remarks> /// Requires an active script context. /// </remarks> /// <param name="promiseRejectionTrackerCallback">The callback function being set.</param> /// <param name="callbackState"> /// User provided state that will be passed back to the callback. /// </param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSetHostPromiseRejectionTracker( promiseRejectionTrackerCallback: JsHostPromiseRejectionTrackerCallback; callbackState: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Retrieve the namespace object for a module. /// </summary> /// <remarks> /// Requires an active script context and that the module has already been evaluated. /// </remarks> /// <param name="requestModule">The JsModuleRecord for which the namespace is being requested.</param> /// <param name="moduleNamespace">A JsValueRef - the requested namespace object.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetModuleNamespace( requestModule: JsModuleRecord; out moduleNamespace: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Determines if a provided object is a JavscriptProxy Object and /// provides references to a Proxy's target and handler. /// </summary> /// <remarks> /// Requires an active script context. /// If object is not a Proxy object the target and handler parameters are not touched. /// If nullptr is supplied for target or handler the function returns after /// setting the isProxy value. /// If the object is a revoked Proxy target and handler are set to JS_INVALID_REFERENCE. /// If it is a Proxy object that has not been revoked target and handler are set to the /// the object's target and handler. /// </remarks> /// <param name="object">The object that may be a Proxy.</param> /// <param name="isProxy">Pointer to a Boolean - is the object a proxy?</param> /// <param name="target">Pointer to a JsValueRef - the object's target.</param> /// <param name="handler">Pointer to a JsValueRef - the object's handler.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsGetProxyProperties( _object: JsValueRef; out isProxy: bool; out target: JsValueRef; out handler: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Parses a script and stores the generated parser state cache into a buffer which can be reused. /// </summary> /// <remarks> /// <para> /// <c>JsSerializeParserState</c> parses a script and then stores a cache of the parser state /// in a runtime-independent format. The parser state may be deserialized in any runtime along /// with the same script to skip the initial parse phase. /// </para> /// <para> /// Requires an active script context. /// </para> /// <para> /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// </para> /// <para> /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// </para> /// </remarks> /// <param name="scriptVal">The script to parse.</param> /// <param name="bufferVal">The buffer to put the serialized parser state cache into.</param> /// <param name="parseAttributes">Encoding for the script.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsSerializeParserState( scriptVal: JsValueRef; out bufferVal: JsValueRef; parseAttributes: JsParseScriptAttributes): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Deserializes the cache of initial parser state and (along with the same /// script source) executes the script and returns the result. /// </summary> /// <remarks> /// <para> /// Requires an active script context. /// </para> /// <para> /// Script source can be either JavascriptString or JavascriptExternalArrayBuffer. /// In case it is an ExternalArrayBuffer, and the encoding of the buffer is Utf16, /// JsParseScriptAttributeArrayBufferIsUtf16Encoded is expected on parseAttributes. /// </para> /// <para> /// Use JavascriptExternalArrayBuffer with Utf8/ASCII script source /// for better performance and smaller memory footprint. /// </para> /// </remarks> /// <param name="script">The script to run.</param> /// <param name="sourceContext"> /// A cookie identifying the script that can be used by debuggable script contexts. /// </param> /// <param name="sourceUrl">The location the script came from</param> /// <param name="parseAttributes">Attribute mask for parsing the script</param> /// <param name="parserState"> /// A buffer containing a cache of the parser state generated by <c>JsSerializeParserState</c>. /// </param> /// <param name="result">The result of the script, if any. This parameter can be null.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsRunScriptWithParserState( script: JsValueRef; sourceContext: JsSourceContext; sourceUrl: JsValueRef; parseAttributes: JsParseScriptAttributes; parserState: JsValueRef; out result: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} implementation uses Math; {$ifdef MSWINDOWS} const _chakracore = 'chakracore.dll'; {$endif} {$ifdef DARWIN} const _chakracore = 'libChakraCore.dylib'; {$endif} {$ifdef LINUX} const _chakracore = 'libChakraCore.so'; {$endif} function JsCreateEnhancedFunction; external _chakracore; function JsInitializeModuleRecord; external _chakracore; function JsParseModuleSource; external _chakracore; function JsModuleEvaluation; external _chakracore; function JsSetModuleHostInfo; external _chakracore; function JsGetModuleHostInfo; external _chakracore; function JsGetAndClearExceptionWithMetadata; external _chakracore; function JsCreateString; external _chakracore; function JsCreateStringUtf16; external _chakracore; function JsCopyString; external _chakracore; function JsCopyStringUtf16; external _chakracore; function JsParse; external _chakracore; function JsRun; external _chakracore; function JsCreatePropertyId; external _chakracore; function JsCopyPropertyId; external _chakracore; function JsSerialize; external _chakracore; function JsParseSerialized; external _chakracore; function JsRunSerialized; external _chakracore; function JsGetPromiseState; external _chakracore; function JsGetPromiseResult; external _chakracore; function JsCreatePromise; external _chakracore; function JsCreateWeakReference; external _chakracore; function JsGetWeakReferenceValue; external _chakracore; function JsCreateSharedArrayBufferWithSharedContent; external _chakracore; function JsGetSharedArrayBufferContent; external _chakracore; function JsReleaseSharedArrayBufferContentHandle; external _chakracore; function JsHasOwnProperty; external _chakracore; function JsCopyStringOneByte; external _chakracore; function JsGetDataViewInfo; external _chakracore; function JsLessThan; external _chakracore; function JsLessThanOrEqual; external _chakracore; function JsCreateExternalObjectWithPrototype; external _chakracore; function JsObjectGetProperty; external _chakracore; function JsObjectSetProperty; external _chakracore; function JsObjectHasProperty; external _chakracore; function JsObjectDefineProperty; external _chakracore; function JsObjectDeleteProperty; external _chakracore; function JsObjectGetOwnPropertyDescriptor; external _chakracore; function JsObjectHasOwnProperty; external _chakracore; function JsSetHostPromiseRejectionTracker; external _chakracore; function JsGetModuleNamespace; external _chakracore; function JsGetProxyProperties; external _chakracore; function JsSerializeParserState; external _chakracore; function JsRunScriptWithParserState; external _chakracore; initialization SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]); finalization end. ================================================ FILE: src/ChakraCoreClasses.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit ChakraCoreClasses; {$include common.inc} interface uses {$ifdef FPC} Types, {$else} Windows, {$endif} Classes, SysUtils, Contnrs, Compat, ChakraCore, ChakraCommon, ChakraCoreUtils; type TChakraCoreContext = class; TChakraModule = class; TMemAllocEvent = procedure (Sender: TObject; Size: NativeUInt; var Allow: Boolean) of object; TMemFreeEvent = procedure (Sender: TObject; Size: NativeUInt) of object; TMemFailureEvent = procedure (Sender: TObject; Size: NativeUInt) of object; TChakraCoreRuntimeOption = ( ccroDisableBackgroundWork, // JsRuntimeAttributeDisableBackgroundWork = $00000001; ccroAllowScriptInterrupt, // JsRuntimeAttributeAllowScriptInterrupt = $00000002; ccroEnableIdleProcessing, // JsRuntimeAttributeEnableIdleProcessing = $00000004; ccroDisableNativeCodeGeneration, // JsRuntimeAttributeDisableNativeCodeGeneration = $00000008; ccroDisableEval, // JsRuntimeAttributeDisableEval = $00000010; ccroEnableExperimentalFeatures, // JsRuntimeAttributeEnableExperimentalFeatures = $00000020; ccroDispatchSetExceptionsToDebugger, // JsRuntimeAttributeDispatchSetExceptionsToDebugger = $00000040; ccroDisableFatalOnOOM, // JsRuntimeAttributeDisableFatalOnOOM = $00000080; ccroDisableExecutablePageAllocation // JsRuntimeAttributeDisableExecutablePageAllocation = $00000100; ); TChakraCoreRuntimeOptions = set of TChakraCoreRuntimeOption; TChakraCoreRuntime = class private FHandle: JsRuntimeHandle; FMemoryLimit: NativeUInt; FOptions: TChakraCoreRuntimeOptions; FOnBeforeCollect: TNotifyEvent; FOnMemAlloc: TMemAllocEvent; FOnMemFailure: TMemFailureEvent; FOnMemFree: TMemFreeEvent; function GetEnabled: Boolean; function GetHandle: JsRuntimeHandle; function GetMemoryLimit: NativeUInt; function GetMemoryUsage: NativeUInt; procedure SetEnabled(Value: Boolean); procedure SetMemoryLimit(Value: NativeUInt); procedure SetOnBeforeCollect(Value: TNotifyEvent); procedure SetOnMemAlloc(Value: TMemAllocEvent); procedure SetOnMemFailure(Value: TMemFailureEvent); procedure SetOnMemFree(Value: TMemFreeEvent); protected procedure CreateRuntime; virtual; procedure DisposeRuntime; virtual; procedure DoBeforeCollect; virtual; function DoMemAlloc(Size: NativeUInt): Boolean; virtual; procedure DoMemFailure(Size: NativeUInt); virtual; procedure DoMemFree(Size: NativeUInt); virtual; public constructor Create(AOptions: TChakraCoreRuntimeOptions = []); virtual; destructor Destroy; override; procedure CollectGarbage; property Enabled: Boolean read GetEnabled write SetEnabled; property Handle: JsRuntimeHandle read GetHandle; property MemoryLimit: NativeUInt read GetMemoryLimit write SetMemoryLimit; property MemoryUsage: NativeUInt read GetMemoryUsage; property Options: TChakraCoreRuntimeOptions read FOptions; property OnBeforeCollect: TNotifyEvent read FOnBeforeCollect write SetOnBeforeCollect; property OnMemAlloc: TMemAllocEvent read FOnMemAlloc write SetOnMemAlloc; property OnMemFailure: TMemFailureEvent read FOnMemFailure write SetOnMemFailure; property OnMemFree: TMemFreeEvent read FOnMemFree write SetOnMemFree; end; TBaseMessage = class private FContext: TChakraCoreContext; protected function Process(out ResultValue: JsValueRef): Boolean; virtual; abstract; public constructor Create(AContext: TChakraCoreContext); virtual; property Context: TChakraCoreContext read FContext; end; TTaskMessage = class(TBaseMessage) private FArgCount: Integer; FArgs: PJsValueRefArray; FDelay: Cardinal; FRepeatCount: Integer; FTask: JsValueRef; FTime: Cardinal; protected function Process(out ResultValue: JsValueRef): Boolean; override; public constructor Create(AContext: TChakraCoreContext; Task, ThisArg: JsValueRef; const Args: array of JsValueRef; ADelay: Cardinal = 0; ARepeatCount: Integer = 1); reintroduce; virtual; destructor Destroy; override; property Delay: Cardinal read FDelay; property RepeatCount: Integer read FRepeatCount; property Task: JsValueRef read FTask; property Time: Cardinal read FTime; end; TPromiseStatus = (psPending, psResolved, psRejected); TPromiseMessage = class(TBaseMessage) private FArgs: array[0..1] of JsValueRef; FPromise: JsValueRef; FRejectTask: JsValueRef; FResolveTask: JsValueRef; FStatus: TPromiseStatus; protected function Process(out ResultValue: JsHandle): Boolean; override; procedure SetStatus(Value: TPromiseStatus; StatusValue: JsValueRef); public constructor Create(AContext: TChakraCoreContext; ThisArg, ResolveTask, RejectTask: JsValueRef); reintroduce; virtual; destructor Destroy; override; property Promise: JsValueRef read FPromise; property RejectTask: JsValueRef read FRejectTask; property ResolveTask: JsValueRef read FResolveTask; property Status: TPromiseStatus read FStatus; end; TModuleMessage = class(TBaseMessage) private FModule: TChakraModule; protected function Process(out ResultValue: JsValueRef): Boolean; override; public constructor Create(AContext: TChakraCoreContext; AModule: TChakraModule); reintroduce; virtual; property Module: TChakraModule read FModule; end; { TChakraModule } TChakraModule = class private FContext: TChakraCoreContext; FHandle: JsModuleRecord; FName: UnicodeString; FParsed: Boolean; FResult: JsvalueRef; FURL: UnicodeString; procedure SetURL(const Value: UnicodeString); public constructor Create(AContext: TChakraCoreContext; const AName: UnicodeString; ARefModule: JsModuleRecord); procedure Parse(const Source: UTF8String); overload; procedure Parse(const Source: UnicodeString); overload; property Context: TChakraCoreContext read FContext; property Handle: JsModuleRecord read FHandle; property Name: UnicodeString read FName; property Parsed: Boolean read FParsed; property Result: JsValueRef read FResult; property URL: UnicodeString read FURL write SetURL; end; TNativeObject = class; TNativeClass = class of TNativeObject; TLoadModuleEvent = procedure(Sender: TObject; Module: TChakraModule) of object; TNativeObjectCreatedEvent = procedure(Sender: TObject; NativeObject: TNativeObject) of object; { TChakraCoreContext } TChakraCoreContext = class private FClassInfos: TList; FGlobal: JsValueRef; FHandle: JsContextRef; FMessageQueue: TQueue; FModules: TStringList; FRuntime: TChakraCoreRuntime; FSourceContext: NativeUInt; FOnActivate: TNotifyEvent; FOnLoadModule: TLoadModuleEvent; FOnNativeObjectCreated: TNativeObjectCreatedEvent; function AddClassInfo(AClass: TNativeClass; AConstructor, APrototype: JsValueRef): Integer; function FindClassInfo(AClass: TNativeClass): Pointer; overload; function FindClassInfo(AConstructor: JsValueRef): Pointer; overload; function GetData: Pointer; function GetHandle: JsContextRef; function GetGlobal: JsValueRef; function GetModuleCount: Integer; function GetModuleNames(Index: Integer): UnicodeString; function GetModules(Index: Integer): TChakraModule; procedure SetData(Value: Pointer); protected procedure ClearModules; function CreateModule(const AName: UnicodeString; ARefModule: JsModuleRecord): TChakraModule; virtual; procedure DoActivate; virtual; procedure DoLoadModule(Module: TChakraModule); virtual; procedure DoNativeObjectCreated(NativeObject: TNativeObject); virtual; procedure DoPromiseContinuation(Task: JsValueRef); virtual; function HandleFetchImportedModuleCallback(referencingModule: JsModuleRecord; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; virtual; function HandleFetchImportedModuleFromScriptCallback(dwReferencingSourceContext: JsSourceContext; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; virtual; function HandleNotifyModuleReadyCallback(referencingModule: JsModuleRecord; exceptionVar: JsValueRef): JsErrorCode; virtual; function ModuleNeeded(const AName: UnicodeString; ARefModule: JsModuleRecord = nil): TChakraModule; procedure ProcessMessages; public constructor Create(ARuntime: TChakraCoreRuntime); destructor Destroy; override; procedure Activate; procedure AddModule(const AName: UTF8String); overload; procedure AddModule(const AName: UnicodeString); overload; function CallFunction(Func: JsValueRef; Args: PJsValueRef; ArgCount: Word): JsValueRef; overload; function CallFunction(Func: JsValueRef; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function CallFunction(const AName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function CallFunction(const AName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function CallNew(const AConstructorName: UTF8String; const Args: array of JsValueRef): JsValueRef; overload; function CallNew(const AConstructorName: UnicodeString; const Args: array of JsValueRef): JsValueRef; overload; class function CurrentContext: TChakraCoreContext; function FindModule(const AName: UnicodeString): TChakraModule; overload; function FindModule(AHandle: JsModuleRecord): TChakraModule; overload; procedure PostMessage(AMessage: TBaseMessage); function RunScript(const Script, AName: UTF8String; IsLibraryCode: Boolean = False): JsValueRef; overload; function RunScript(const Script, AName: UnicodeString; IsLibraryCode: Boolean = False): JsValueRef; overload; property Data: Pointer read GetData write SetData; property Global: JsValueRef read GetGlobal; property Handle: JsContextRef read GetHandle; property ModuleCount: Integer read GetModuleCount; property ModuleNames[Index: Integer]: UnicodeString read GetModuleNames; property Modules[Index: Integer]: TChakraModule read GetModules; property Runtime: TChakraCoreRuntime read FRuntime; property OnActivate: TNotifyEvent read FOnActivate write FOnActivate; property OnLoadModule: TLoadModuleEvent read FOnLoadModule write FOnLoadModule; property OnNativeObjectCreated: TNativeObjectCreatedEvent read FOnNativeObjectCreated write FOnNativeObjectCreated; end; { TNativeArrayBuffer } TChakraCoreNativeArrayBuffer = class private FBuffer: Pointer; FBufferSize: Integer; FHandle: JsValueRef; public constructor Create(ABufferSize: Integer); virtual; destructor Destroy; override; property Buffer: Pointer read FBuffer; property BufferSize: Integer read FBufferSize; property Handle: JsValueRef read FHandle; end; TNativeMethod = function(Args: PJsValueRef; ArgCount: Word): JsValueRef of object; TNativeGetAccessorMethod = function: JsValueRef of object; TNativeSetAccessorMethod = procedure(Value: JsValueRef) of object; { TNativeObject } TNativeObject = class private FInstance: JsValueRef; function GetContext: TChakraCoreContext; function GetContextHandle: JsContextRef; protected class function FindConstructor: JsValueRef; class function FindParentConstructor: JsValueRef; class function FindPrototype: JsValueRef; class procedure InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); virtual; class function InitializePrototype(AConstructor: JsValueRef): JsValueRef; virtual; class procedure RegisterClassMethod(AConstructor: JsValueRef; const AName: UnicodeString; AMethod: Pointer; UseStrictRules: Boolean = True); virtual; class procedure RegisterMethod(AInstance: JsValueRef; const AName: UnicodeString; AMethod: Pointer; UseStrictRules: Boolean = True); virtual; class procedure RegisterMethods(AInstance: JsValueRef); virtual; class procedure RegisterNamedProperty(AInstance: JsValueRef; const AName: UnicodeString; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: Pointer); overload; virtual; class procedure RegisterNamedProperty(AInstance: JsValueRef; const AName: UnicodeString; Configurable, Enumerable, Writable: Boolean; Value: JsValueRef); overload; virtual; class procedure RegisterProperties(AInstance: JsValueRef); virtual; public constructor Create(Args: PJsValueRef = nil; ArgCount: Word = 0; AFinalize: Boolean = False); overload; virtual; constructor Create(const Args: array of JsValueRef; AFinalize: Boolean = False); overload; virtual; destructor Destroy; override; function AddRef: Integer; class procedure Project(const AName: UnicodeString = ''; Scope: JsValueRef = nil; UseStrictRules: Boolean = True); overload; virtual; function Release: Integer; property Context: TChakraCoreContext read GetContext; property ContextHandle: JsContextRef read GetContextHandle; property Instance: JsValueRef read FInstance; end; implementation type PNativeClassInfo = ^TNativeClassInfo; TNativeClassInfo = record AClass: TNativeClass; AConstructor: JsValueRef; APrototype: JsValueRef; end; procedure BeforeCollectCallback(callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin if Assigned(callbackState) then TChakraCoreRuntime(callbackState).DoBeforeCollect; end; function ThreadServiceCallback(callback: JsBackgroundWorkItemCallback; callbackState: Pointer): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := False; // let ChakraCore handle this work item // TODO // Result := True; // CurrentRuntime.DoBackgroundWork(callback, callbackState); end; function FetchImportedModuleCallBack(referencingModule: JsModuleRecord; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := TChakraCoreContext.CurrentContext.HandleFetchImportedModuleCallback(referencingModule, specifier, dependentModuleRecord); end; function FetchImportedModuleFromScriptCallBack(dwReferencingSourceContext: JsSourceContext; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := TChakraCoreContext.CurrentContext.HandleFetchImportedModuleFromScriptCallback(dwReferencingSourceContext, specifier, dependentModuleRecord); end; function MemoryAllocationCallback(callbackState: Pointer; allocationEvent: JsMemoryEventType; allocationSize: size_t): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := True; if Assigned(callbackState) then case allocationEvent of JsMemoryAllocate: Result := TChakraCoreRuntime(callbackState).DoMemAlloc(allocationSize); JsMemoryFree: TChakraCoreRuntime(callbackState).DoMemFree(allocationSize); JsMemoryFailure: TChakraCoreRuntime(callbackState).DoMemFailure(allocationSize); end; end; procedure Native_FinalizeCallback(data: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin TObject(data).Free; end; function Native_ConstructorCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var NativeClass: TNativeClass absolute CallbackState; NativeInstance: TNativeObject; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native constructor callback: state not assigned'); if not Assigned(Args) then raise Exception.Create('Native constructor callback: arguments not assigned'); if ArgCount < 1 then raise Exception.CreateFmt('Native constructor callback: invalid argument count %d', [ArgCount]); if IsConstructCall then begin Inc(Args); Dec(ArgCount); NativeInstance := NativeClass.Create(Pointer(Args), ArgCount, True); Result := NativeInstance.Instance; end else begin Result := Args^; Inc(Args); Dec(ArgCount); NativeClass.InitializeInstance(Result, Args, ArgCount); end; except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function Native_GetConstructorCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var NativeClass: TNativeClass absolute CallbackState; Context: TChakraCoreContext; Info: PNativeClassInfo; AConstructor, APrototype: JsValueRef; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native constructor getter callback: state not assigned'); if IsConstructCall then raise Exception.Create('Native constructor getter callback: called as a constructor'); Context := TChakraCoreContext.CurrentContext; Info := Context.FindClassInfo(NativeClass); if Assigned(Info) then Result := Info^.AConstructor else begin AConstructor := JsCreateFunction(Native_ConstructorCallback, CallbackState, JsStringToUnicodeString(JsGetProperty(Callee, 'name'))); JsAddRef(AConstructor); APrototype := NativeClass.InitializePrototype(AConstructor); NativeClass.RegisterMethods(APrototype); NativeClass.RegisterProperties(APrototype); JsSetProperty(AConstructor, 'prototype', APrototype); JsSetProperty(APrototype, 'constructor', AConstructor); Context.AddClassInfo(NativeClass, AConstructor, APrototype); Result := AConstructor; end; except on E: Exception do JsThrowError(Format('[%s] %s', [E.ClassName, E.Message])); end; end; function Native_ClassMethodCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var Context: TChakraCoreContext; Info: PNativeClassInfo; NativeMethod: TNativeMethod; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native class method callback: state not assigned'); if IsConstructCall then raise Exception.Create('Native class method callback: called as a constructor'); if not Assigned(Args) then raise Exception.Create('Native class method callback: arguments not assigned'); if ArgCount < 1 then raise Exception.CreateFmt('Native class method callback: invalid argument count %d', [ArgCount]); if (JsGetValueType(Args^) <> JsFunction) then raise Exception.Create('Native class method callback: thisarg not a function'); Context := TChakraCoreContext.CurrentContext; Info := Context.FindClassInfo(Args^); if not Assigned(Info) then raise Exception.CreateFmt('Native class not found for %s', [JsStringToUnicodeString(JsGetProperty(Args^, 'name'))]); TMethod(NativeMethod).Code := CallbackState; TMethod(NativeMethod).Data := Info^.AClass; Inc(Args); Dec(ArgCount); Result := NativeMethod(Args, ArgCount); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function Native_MethodCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var NativeMethod: TNativeMethod; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native method callback: state not assigned'); if IsConstructCall then raise Exception.Create('Native method callback: called as a constructor'); if not Assigned(Args) then raise Exception.Create('Native method callback: arguments not assigned'); if ArgCount < 1 then raise Exception.CreateFmt('Native method callback: invalid argument count %d', [ArgCount]); if (JsGetValueType(Args^) <> JsObject) then raise Exception.Create('Native method callback: thisarg not an object'); TMethod(NativeMethod).Code := CallbackState; TMethod(NativeMethod).Data := JsGetExternalData(Args^); if not Assigned(TMethod(NativeMethod).Data) then raise Exception.Create('Native method callback: external data not assigned'); if Args^ <> TNativeObject(TMethod(NativeMethod).Data).Instance then raise Exception.Create('Native method callback: thisarg not the registered instance'); Inc(Args); Dec(ArgCount); Result := NativeMethod(Args, ArgCount); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function Native_PropGetCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var NativeMethod: TNativeGetAccessorMethod; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native getter callback: state not assigned'); if IsConstructCall then raise Exception.Create('Native getter callback: called as a constructor'); if not Assigned(Args) then raise Exception.Create('Native getter callback: arguments not assigned'); if ArgCount <> 1 then // thisarg raise Exception.CreateFmt('Native getter callback: invalid argument count %d', [ArgCount]); TMethod(NativeMethod).Code := CallbackState; TMethod(NativeMethod).Data := JsGetExternalData(Args^); if not Assigned(TMethod(NativeMethod).Data) then raise Exception.Create('Native getter callback: external data not assigned'); if Args^ <> TNativeObject(TMethod(NativeMethod).Data).Instance then raise Exception.Create('Native getter callback: thisarg not the registered instance'); Result := NativeMethod; except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function Native_PropSetCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRefArray; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var NativeMethod: TNativeSetAccessorMethod; begin Result := JsUndefinedValue; try if not Assigned(CallbackState) then raise Exception.Create('Native setter callback: state not assigned'); if IsConstructCall then raise Exception.Create('Native setter callback: called as a constructor'); if not Assigned(Args) then raise Exception.Create('Native setter callback: arguments not assigned'); if ArgCount <> 2 then // thisarg, value raise Exception.CreateFmt('Native setter callback: invalid argument count %d', [ArgCount]); TMethod(NativeMethod).Code := CallbackState; TMethod(NativeMethod).Data := JsGetExternalData(Args^[0]); if not Assigned(TMethod(NativeMethod).Data) then raise Exception.Create('Native setter callback: external data not assigned'); if Args^[0] <> TNativeObject(TMethod(NativeMethod).Data).Instance then raise Exception.Create('Native setter callback: thisarg not the registered instance'); NativeMethod(Args^[1]); except on E: Exception do JsThrowError(WideFormat('[%s] %s', [E.ClassName, E.Message])); end; end; function NotifyModuleReadyCallback(referencingModule: JsModuleRecord; exceptionVar: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := TChakraCoreContext.CurrentContext.HandleNotifyModuleReadyCallback(referencingModule, exceptionVar); end; function RuntimeOptionsToJsRuntimeAttributes(Value: TChakraCoreRuntimeOptions): Cardinal; begin Result := JsRuntimeAttributeNone; if ccroDisableBackgroundWork in Value then Result := Result or JsRuntimeAttributeDisableBackgroundWork; if ccroAllowScriptInterrupt in Value then Result := Result or JsRuntimeAttributeAllowScriptInterrupt; if ccroEnableIdleProcessing in Value then Result := Result or JsRuntimeAttributeEnableIdleProcessing; if ccroDisableNativeCodeGeneration in Value then Result := Result or JsRuntimeAttributeDisableNativeCodeGeneration; if ccroDisableEval in Value then Result := Result or JsRuntimeAttributeDisableEval; if ccroEnableExperimentalFeatures in Value then Result := Result or JsRuntimeAttributeEnableExperimentalFeatures; if ccroDispatchSetExceptionsToDebugger in Value then Result := Result or JsRuntimeAttributeDispatchSetExceptionsToDebugger; if ccroDisableFatalOnOOM in Value then Result := Result or JsRuntimeAttributeDisableFatalOnOOM; if ccroDisableExecutablePageAllocation in Value then Result := Result or JsRuntimeAttributeDisableExecutablePageAllocation; end; { TChakraCoreRuntime private } function TChakraCoreRuntime.GetEnabled: Boolean; var Disabled: ByteBool; begin if FHandle = JS_INVALID_RUNTIME_HANDLE then Result := False else begin ChakraCoreCheck(JsIsRuntimeExecutionDisabled(FHandle, Disabled)); Result := not Disabled; end; end; function TChakraCoreRuntime.GetHandle: JsRuntimeHandle; begin if FHandle = JS_INVALID_RUNTIME_HANDLE then CreateRuntime; Result := FHandle; end; function TChakraCoreRuntime.GetMemoryLimit: NativeUInt; begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then ChakraCoreCheck(JsGetRuntimeMemoryLimit(FHandle, FMemoryLimit)); Result := FMemoryLimit; end; function TChakraCoreRuntime.GetMemoryUsage: NativeUInt; begin Result := 0; if FHandle <> JS_INVALID_RUNTIME_HANDLE then ChakraCoreCheck(JsGetRuntimeMemoryUsage(FHandle, Result)); end; procedure TChakraCoreRuntime.SetEnabled(Value: Boolean); begin if Value <> Enabled then begin if Value then ChakraCoreCheck(JsEnableRuntimeExecution(Handle)) else ChakraCoreCheck(JsDisableRuntimeExecution(Handle)); end; end; procedure TChakraCoreRuntime.SetMemoryLimit(Value: NativeUInt); begin if Value <> FMemoryLimit then begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then ChakraCoreCheck(JsSetRuntimeMemoryLimit(FHandle, Value)); FMemoryLimit := Value; end; end; procedure TChakraCoreRuntime.SetOnBeforeCollect(Value: TNotifyEvent); begin if @Value <> @FOnBeforeCollect then begin FOnBeforeCollect := Value; end; end; procedure TChakraCoreRuntime.SetOnMemAlloc(Value: TMemAllocEvent); begin if @Value <> @FOnMemAlloc then begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then begin if Assigned(Value) or Assigned(FOnMemFailure) or Assigned(FOnMemFree) then ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, MemoryAllocationCallback)) else ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, nil)); end; FOnMemAlloc := Value; end; end; procedure TChakraCoreRuntime.SetOnMemFailure(Value: TMemFailureEvent); begin if @Value <> @FOnMemFailure then begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then begin if Assigned(Value) or Assigned(FOnMemAlloc) or Assigned(FOnMemFree) then ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, MemoryAllocationCallback)) else ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, nil)); end; FOnMemFailure := Value; end; end; procedure TChakraCoreRuntime.SetOnMemFree(Value: TMemFreeEvent); begin if @Value <> @FOnMemFree then begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then begin if Assigned(Value) or Assigned(FOnMemAlloc) or Assigned(FOnMemFailure) then ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, MemoryAllocationCallback)) else ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, nil)); end; FOnMemFree := Value; end; end; { TChakraCoreRuntime protected } procedure TChakraCoreRuntime.CreateRuntime; begin if FHandle <> JS_INVALID_RUNTIME_HANDLE then Exit; ChakraCoreCheck(JsCreateRuntime(JsRuntimeAttributes(RuntimeOptionsToJsRuntimeAttributes(FOptions)), ThreadServiceCallback, FHandle)); try if NativeInt(FMemoryLimit) <> -1 then ChakraCoreCheck(JsSetRuntimeMemoryLimit(FHandle, FMemoryLimit)); if Assigned(FOnMemAlloc) or Assigned(FOnMemFailure) or Assigned(FOnMemFree) then ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, MemoryAllocationCallback)); if Assigned(FOnBeforeCollect) then ChakraCoreCheck(JsSetRuntimeBeforeCollectCallback(FHandle, Self, BeforeCollectCallback)); except JsDisposeRuntime(FHandle); FHandle := JS_INVALID_RUNTIME_HANDLE; raise; end; end; procedure TChakraCoreRuntime.DisposeRuntime; begin if FHandle = JS_INVALID_RUNTIME_HANDLE then Exit; ChakraCoreCheck(JsSetCurrentContext(JS_INVALID_REFERENCE)); ChakraCoreCheck(JsSetRuntimeMemoryAllocationCallback(FHandle, Self, nil)); ChakraCoreCheck(JsDisposeRuntime(FHandle)); FHandle := JS_INVALID_RUNTIME_HANDLE; end; procedure TChakraCoreRuntime.DoBeforeCollect; begin if Assigned(FOnBeforeCollect) then FOnBeforeCollect(Self); end; function TChakraCoreRuntime.DoMemAlloc(Size: NativeUInt): Boolean; begin Result := True; if Assigned(FOnMemAlloc) then FOnMemAlloc(Self, Size, Result); end; procedure TChakraCoreRuntime.DoMemFailure(Size: NativeUInt); begin if Assigned(FOnMemFailure) then FOnMemFailure(Self, Size); end; procedure TChakraCoreRuntime.DoMemFree(Size: NativeUInt); begin if Assigned(FOnMemFree) then FOnMemFree(Self, Size); end; { TChakraCoreRuntime public } constructor TChakraCoreRuntime.Create(AOptions: TChakraCoreRuntimeOptions); begin inherited Create; FHandle := JS_INVALID_RUNTIME_HANDLE; FMemoryLimit := NativeUInt(NativeInt(-1)); FOnMemAlloc := nil; FOnMemFailure := nil; FOnMemFree := nil; FOptions := AOptions; end; destructor TChakraCoreRuntime.Destroy; begin DisposeRuntime; inherited Destroy; end; procedure TChakraCoreRuntime.CollectGarbage; begin if Enabled then ChakraCoreCheck(JsCollectGarbage(Handle)); end; { TBaseMessage public } constructor TBaseMessage.Create(AContext: TChakraCoreContext); begin inherited Create; FContext := AContext; end; { TCallbackMessage protected } function TTaskMessage.Process(out ResultValue: JsValueRef): Boolean; var Ticks: Cardinal; begin ResultValue := JsUndefinedValue; Ticks := GetTickCount; Result := Ticks >= FTime + FDelay; if Result then begin ResultValue := JsCallFunction(FTask, @FArgs^[0], FArgCount + 1); if FRepeatCount > 0 then Dec(FRepeatCount); if FRepeatCount = 0 then Exit; Result := False; ResultValue := JsUndefinedValue; FTime := GetTickCount; end; end; { TCallbackMessage public } constructor TTaskMessage.Create(AContext: TChakraCoreContext; Task, ThisArg: JsValueRef; const Args: array of JsValueRef; ADelay: Cardinal; ARepeatCount: Integer); var I: Integer; begin inherited Create(AContext); FTask := Task; JsAddRef(FTask); FArgCount := Length(Args); FArgs := AllocMem((FArgCount + 1) * SizeOf(PJsValueRef)); if Assigned(ThisArg) then FArgs^[0] := ThisArg else FArgs^[0] := Context.Global; JsAddRef(FArgs^[0]); for I := 1 to FArgCount do begin FArgs^[I] := Args[I - 1]; JsAddRef(FArgs^[I]); end; FDelay := ADelay; FRepeatCount := ARepeatCount; FTime := GetTickCount; end; destructor TTaskMessage.Destroy; var I: Integer; begin if Assigned(FArgs) then begin for I := 0 to FArgCount do if Assigned(FArgs^[I]) then JsRelease(FArgs^[I]); FreeMem(FArgs); end; FArgs := nil; FArgCount := 0; if Assigned(FTask) then JsRelease(FTask); FTask := nil; inherited Destroy; end; { TPromiseMessage protected } function TPromiseMessage.Process(out ResultValue: JsHandle): Boolean; begin Result := False; ResultValue := JsUndefinedValue; case FStatus of psPending: Exit; psResolved: ResultValue := JsCallFunction(FResolveTask, @FArgs[0], 2); psRejected: ResultValue := JsCallFunction(FRejectTask, @Fargs[0], 2); end; Result := True; end; procedure TPromiseMessage.SetStatus(Value: TPromiseStatus; StatusValue: JsValueRef); begin FArgs[1] := StatusValue; FStatus := Value; end; { TPromiseMessage public } constructor TPromiseMessage.Create(AContext: TChakraCoreContext; ThisArg, ResolveTask, RejectTask: JsValueRef); begin inherited Create(AContext); FArgs[0] := ThisArg; JsAddRef(FArgs[0]); FArgs[1] := nil; FResolveTask := ResolveTask; JsAddRef(FResolveTask); FRejectTask := RejectTask; JsAddRef(FRejectTask); end; destructor TPromiseMessage.Destroy; begin if Assigned(FRejectTask) then JsRelease(FRejectTask); FRejectTask := nil; if Assigned(FResolveTask) then JsRelease(FResolveTask); FResolveTask := nil; if Assigned(FArgs[0]) then JsRelease(FArgs[0]); FArgs[0] := nil; if Assigned(FArgs[1]) then JsRelease(FArgs[1]); FArgs[1] := nil; inherited Destroy; end; { TModuleMessage protected } function TModuleMessage.Process(out ResultValue: JsValueRef): Boolean; begin ChakraCoreCheck(JsModuleEvaluation(FModule.Handle, FModule.FResult)); Result := True; ResultValue := FModule.FResult; end; { TModuleMessage public } constructor TModuleMessage.Create(AContext: TChakraCoreContext; AModule: TChakraModule); begin inherited Create(AContext); FModule := AModule; end; { TChakraModule public } constructor TChakraModule.Create(AContext: TChakraCoreContext; const AName: UnicodeString; ARefModule: JsModuleRecord); var Specifier: JsValueRef; begin inherited Create; FContext := AContext; FName := AName; FURL := ''; FResult := JsUndefinedValue; Specifier := JS_INVALID_REFERENCE; if AName <> '' then Specifier := StringToJsString(AName); ChakraCoreCheck(JsInitializeModuleRecord(ARefModule, Specifier, FHandle)); ChakraCoreCheck(JsSetModuleHostInfo(FHandle, JsModuleHostInfo_FetchImportedModuleCallback, @FetchImportedModuleCallback)); ChakraCoreCheck(JsSetModuleHostInfo(FHandle, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, @FetchImportedModuleFromScriptCallback)); ChakraCoreCheck(JsSetModuleHostInfo(FHandle, JsModuleHostInfo_NotifyModuleReadyCallback, @NotifyModuleReadyCallback)); ChakraCoreCheck(JsSetModuleHostInfo(FHandle, JsModuleHostInfo_HostDefined, Specifier)); end; procedure TChakraModule.Parse(const Source: UTF8String); var Error: JsValueRef; begin if not FParsed then begin ChakraCoreCheck(JsParseModuleSource(Handle, 0, PByte(PAnsiChar(Source)), Length(Source), JsParseModuleSourceFlags_DataIsUTF8, Error)); FParsed := True; end; end; procedure TChakraModule.Parse(const Source: UnicodeString); var Error: JsValueRef; begin if not FParsed then begin ChakraCoreCheck(JsParseModuleSource(Handle, 0, PByte(PUnicodeChar(Source)), Length(Source) * SizeOf(UnicodeChar), JsParseModuleSourceFlags_DataIsUTF16LE, Error)); FParsed := True; end; end; procedure TChakraModule.SetURL(const Value: UnicodeString); var Specifier: JsValueRef; begin if Value <> FURL then begin Specifier := JS_INVALID_REFERENCE; if Value <> '' then Specifier := StringToJsString(Value); ChakraCoreCheck(JsSetModuleHostInfo(FHandle, JsModuleHostInfo_Url, Specifier)); FURL := Value; end; end; procedure PromiseContinuation(task: JsValueRef; callbackState: Pointer); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin if Assigned(callbackState) then TChakraCoreContext(callbackState).DoPromiseContinuation(task); end; { TChakraCoreContext private } function TChakraCoreContext.AddClassInfo(AClass: TNativeClass; AConstructor, APrototype: JsValueRef): Integer; var Info: PNativeClassInfo; begin if JsGetValueType(AConstructor) <> JsFunction then raise Exception.CreateFmt('Constructor for native class ''%s'' not a function', [AClass.ClassName]); if not Assigned(APrototype) then APrototype := JsGetProperty(AConstructor, UnicodeString('prototype')); if JsGetValueType(APrototype) <> JsObject then raise Exception.CreateFmt('Prototype for native class ''%s'' not an object', [AClass.ClassName]); GetMem(Info, SizeOf(TNativeClassInfo)); try Info^.AClass := AClass; Info^.AConstructor := AConstructor; Info^.APrototype := APrototype; Result := FClassInfos.Add(Info); except FreeMem(Info); raise; end; end; function TChakraCoreContext.FindClassInfo(AClass: TNativeClass): Pointer; var I: Integer; Info: PNativeClassInfo; begin Result := nil; for I := 0 to FClassInfos.Count - 1 do begin Info := FClassInfos[I]; if Info^.AClass = AClass then begin Result := Info; Break; end; end; end; function TChakraCoreContext.FindClassInfo(AConstructor: JsValueRef): Pointer; var I: Integer; Info: PNativeClassInfo; begin Result := nil; for I := 0 to FClassInfos.Count - 1 do begin Info := FClassInfos[I]; if Info^.AConstructor = AConstructor then begin Result := Info; Break; end; end; end; function TChakraCoreContext.GetData: Pointer; begin ChakraCoreCheck(JsGetContextData(FHandle, Result)); end; function TChakraCoreContext.GetGlobal: JsValueRef; begin if FGlobal = JS_INVALID_REFERENCE then FGlobal := JsGlobal; Result := FGlobal; end; function TChakraCoreContext.GetHandle: JsContextRef; begin if FHandle = JS_INVALID_REFERENCE then begin ChakraCoreCheck(JsCreateContext(FRuntime.Handle, FHandle)); ChakraCoreCheck(JsSetContextData(FHandle, Self)); end; Result := FHandle; end; function TChakraCoreContext.GetModuleCount: Integer; begin Result := FModules.Count; end; function TChakraCoreContext.GetModuleNames(Index: Integer): UnicodeString; begin {$ifdef UNICODE} Result := FModules[Index]; {$else} Result := UTF8Decode(FModules[Index]); {$endif} end; function TChakraCoreContext.GetModules(Index: Integer): TChakraModule; begin Result := TChakraModule(FModules.Objects[Index]); end; procedure TChakraCoreContext.SetData(Value: Pointer); begin ChakraCoreCheck(JsSetContextData(FHandle, Value)); end; { TChakraCoreContext protected } procedure TChakraCoreContext.ClearModules; var I: Integer; begin for I := 0 to FModules.Count - 1 do FModules.Objects[I].Free; FModules.Clear; end; function TChakraCoreContext.CreateModule(const AName: UnicodeString; ARefModule: JsModuleRecord): TChakraModule; begin Result := TChakraModule.Create(Self, AName, ARefModule); try {$ifdef UNICODE} FModules.AddObject(AName, Result); {$else} FModules.AddObject(UTF8Encode(AName), Result); {$endif} except Result.Free; raise; end; end; procedure TChakraCoreContext.DoActivate; begin if Assigned(FOnActivate) then FOnActivate(Self); end; procedure TChakraCoreContext.DoLoadModule(Module: TChakraModule); begin if Assigned(FOnLoadModule) then FOnLoadModule(Self, Module); end; procedure TChakraCoreContext.DoNativeObjectCreated(NativeObject: TNativeObject); begin if Assigned(FOnNativeObjectCreated) then FOnNativeObjectCreated(Self, NativeObject); end; procedure TChakraCoreContext.DoPromiseContinuation(Task: JsValueRef); var AMessage: TTaskMessage; begin AMessage := TTaskMessage.Create(Self, Task, nil, []); try PostMessage(AMessage); except AMessage.Free; raise; end; end; function TChakraCoreContext.HandleFetchImportedModuleCallback(referencingModule: JsModuleRecord; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; var ModuleName: UnicodeString; Module: TChakraModule; begin Result := JsNoError; dependentModuleRecord := JS_INVALID_REFERENCE; ModuleName := JsStringToUnicodeString(specifier); Module := ModuleNeeded(ModuleName, referencingModule); dependentModuleRecord := Module.Handle; end; function TChakraCoreContext.HandleFetchImportedModuleFromScriptCallback(dwReferencingSourceContext: JsSourceContext; specifier: JsValueRef; out dependentModuleRecord: JsModuleRecord): JsErrorCode; var ModuleName: UnicodeString; Module: TChakraModule; begin Result := JsNoError; dependentModuleRecord := JS_INVALID_REFERENCE; ModuleName := JsStringToUnicodeString(specifier); Module := ModuleNeeded(ModuleName); dependentModuleRecord := Module.Handle; end; function TChakraCoreContext.HandleNotifyModuleReadyCallback(referencingModule: JsModuleRecord; exceptionVar: JsValueRef): JsErrorCode; var Module: TChakraModule; AMessage: TModuleMessage; begin Result := JsNoError; if Assigned(exceptionVar) then RaiseError(exceptionVar); Module := FindModule(referencingModule); if Assigned(Module) then begin AMessage := TModuleMessage.Create(Self, Module); try FMessageQueue.Push(AMessage); except AMessage.Free; raise; end; end; end; function TChakraCoreContext.ModuleNeeded(const AName: UnicodeString; ARefModule: JsModuleRecord): TChakraModule; begin Result := FindModule(AName); if not Assigned(Result) then begin Result := CreateModule(AName, ARefModule); if AName <> '' then DoLoadModule(Result); end; end; procedure TChakraCoreContext.ProcessMessages; var AMessage: TBaseMessage; ResultValue: JsValueRef; begin while FMessageQueue.Count > 0 do begin AMessage := FMessageQueue.Pop; if AMessage.Process(ResultValue) then AMessage.Free else FMessageQueue.Push(AMessage); end; end; { TChakraCoreContext public } constructor TChakraCoreContext.Create(ARuntime: TChakraCoreRuntime); begin inherited Create; FMessageQueue := nil; FModules := nil; FRuntime := ARuntime; FHandle := JS_INVALID_REFERENCE; FGlobal := JS_INVALID_REFERENCE; FMessageQueue := TQueue.Create; FModules := TStringList.Create; FModules.Duplicates := dupError; FModules.Sorted := True; FSourceContext := 0; FClassInfos := TList.Create; end; destructor TChakraCoreContext.Destroy; var I: Integer; begin for I := FClassInfos.Count - 1 downto 0 do begin JsRelease(PNativeClassInfo(FClassInfos[I])^.AConstructor); FreeMem(FClassInfos[I]); end; FreeAndNil(FClassInfos); FGlobal := JS_INVALID_REFERENCE; FHandle := JS_INVALID_REFERENCE; FRuntime := nil; ClearModules; FModules.Free; FMessageQueue.Free; inherited Destroy; end; procedure TChakraCoreContext.Activate; begin ChakraCoreCheck(JsSetCurrentContext(Handle)); ChakraCoreCheck(JsSetPromiseContinuationCallback(PromiseContinuation, Self)); DoActivate; end; procedure TChakraCoreContext.AddModule(const AName: UTF8String); begin AddModule(UTF8ToString(AName)); end; procedure TChakraCoreContext.AddModule(const AName: UnicodeString); begin Activate; ModuleNeeded(AName); end; function TChakraCoreContext.CallFunction(Func: JsValueRef; Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := JsCallFunction(Func, Args, ArgCount); ProcessMessages; end; function TChakraCoreContext.CallFunction(Func: JsValueRef; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; begin Result := JsCallFunction(Func, Args, ThisArg); ProcessMessages; end; function TChakraCoreContext.CallFunction(const AName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; begin Result := JsCallFunction(AName, Args, ThisArg); ProcessMessages; end; function TChakraCoreContext.CallFunction(const AName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; begin Result := CallFunction(UTF8Encode(AName), Args, ThisArg); end; function TChakraCoreContext.CallNew(const AConstructorName: UTF8String; const Args: array of JsValueRef): JsValueRef; begin Result := JsNew(AConstructorName, Args); ProcessMessages; end; function TChakraCoreContext.CallNew(const AConstructorName: UnicodeString; const Args: array of JsValueRef): JsValueRef; begin Result := JsNew(AConstructorName, Args); ProcessMessages; end; class function TChakraCoreContext.CurrentContext: TChakraCoreContext; begin ChakraCoreCheck(JsGetContextData(JsGetCurrentContext, Pointer(Result))); end; function TChakraCoreContext.FindModule(const AName: UnicodeString): TChakraModule; var Index: Integer; begin Result := nil; ProcessMessages; {$ifdef UNICODE} if FModules.Find(AName, Index) then {$else} if FModules.Find(UTF8Encode(AName), Index) then {$endif} Result := Modules[Index]; end; function TChakraCoreContext.FindModule(AHandle: JsModuleRecord): TChakraModule; var I: Integer; begin Result := nil; for I := 0 to ModuleCount - 1 do if Modules[I].Handle = AHandle then begin Result := Modules[I]; Break; end; end; procedure TChakraCoreContext.PostMessage(AMessage: TBaseMessage); begin FMessageQueue.Push(AMessage); end; function TChakraCoreContext.RunScript(const Script, AName: UTF8String; IsLibraryCode: Boolean): JsValueRef; begin if ModuleCount = 0 then AddModule(''); Result := JsRunScript(Script, AName, FSourceContext, IsLibraryCode); Inc(FSourceContext); ProcessMessages; end; function TChakraCoreContext.RunScript(const Script, AName: UnicodeString; IsLibraryCode: Boolean): JsValueRef; begin if ModuleCount = 0 then AddModule(''); Result := JsRunScript(Script, AName, FSourceContext, IsLibraryCode); Inc(FSourceContext); ProcessMessages; end; { TChakraCoreNativeArrayBuffer public } constructor TChakraCoreNativeArrayBuffer.Create(ABufferSize: Integer); begin inherited Create; FBuffer := AllocMem(ABufferSize); FBufferSize := ABufferSize; ChakraCoreCheck(JsCreateExternalArrayBuffer(FBuffer, FBufferSize, Native_FinalizeCallback, Self, FHandle)); end; destructor TChakraCoreNativeArrayBuffer.Destroy; begin if Assigned(FBuffer) then FreeMem(FBuffer); inherited Destroy; end; { TNativeObject private } function TNativeObject.GetContext: TChakraCoreContext; var P: Pointer absolute Result; begin ChakraCoreCheck(JsGetContextData(ContextHandle, P)); end; function TNativeObject.GetContextHandle: JsContextRef; begin ChakraCoreCheck(JsGetContextOfObject(FInstance, Result)); end; { TNativeObject protected } class function TNativeObject.FindConstructor: JsValueRef; var Info: PNativeClassInfo; begin Result := nil; if Self.ClassParent <> TNativeObject then begin Info := TChakraCoreContext.CurrentContext.FindClassInfo(Self); if Assigned(Info) then Result := Info^.AConstructor; end; end; class function TNativeObject.FindParentConstructor: JsValueRef; var Info: PNativeClassInfo; begin Result := nil; if Self.ClassParent <> TNativeObject then begin Info := TChakraCoreContext.CurrentContext.FindClassInfo(TNativeClass(Self.ClassParent)); if Assigned(Info) then Result := Info^.AConstructor; end; end; class function TNativeObject.FindPrototype: JsValueRef; var Info: PNativeClassInfo; begin Result := nil; Info := TChakraCoreContext.CurrentContext.FindClassInfo(Self); if Assigned(Info) then Result := Info^.APrototype; end; class procedure TNativeObject.InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); var ParentConstructor: JsValueRef; ParentArgs: JsValueRefArray; begin ParentConstructor := FindParentConstructor; if Assigned(ParentConstructor) and (Self.ClassParent <> TNativeObject) then begin // pass thisarg + args SetLength(ParentArgs, ArgCount + 1); ParentArgs[0] := AInstance; if ArgCount > 0 then Move(Args^, ParentArgs[1], ArgCount * SizeOf(JsValueRef)); JsCallFunction(ParentConstructor, @ParentArgs[0], ArgCount + 1); end; end; class function TNativeObject.InitializePrototype(AConstructor: JsValueRef): JsValueRef; begin if Self.ClassParent = TNativeObject then Result := JsGetProperty(AConstructor, 'prototype') else Result := JsCreateObject(JsGetProperty(FindParentConstructor, 'prototype')); end; class procedure TNativeObject.RegisterClassMethod(AConstructor: JsValueRef; const AName: UnicodeString; AMethod: Pointer; UseStrictRules: Boolean); begin JsSetCallback(AConstructor, AName, Native_ClassMethodCallback, AMethod, UseStrictRules); end; class procedure TNativeObject.RegisterMethod(AInstance: JsValueRef; const AName: UnicodeString; AMethod: Pointer; UseStrictRules: Boolean); begin JsSetCallback(AInstance, AName, Native_MethodCallback, AMethod, UseStrictRules); end; class procedure TNativeObject.RegisterMethods(AInstance: JsValueRef); begin // do nothing end; class procedure TNativeObject.RegisterNamedProperty(AInstance: JsValueRef; const AName: UnicodeString; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: Pointer); var GetFunc, SetFunc: JsValueRef; begin GetFunc := nil; SetFunc := nil; if Assigned(GetAccessor) then GetFunc := JsCreateFunction(@Native_PropGetCallback, GetAccessor, UnicodeString('')); if Assigned(SetAccessor) then SetFunc := JsCreateFunction(@Native_PropSetCallback, SetAccessor, UnicodeString('')); JsDefineProperty(AName, Configurable, Enumerable, GetFunc, SetFunc, AInstance); end; class procedure TNativeObject.RegisterNamedProperty(AInstance: JsValueRef; const AName: UnicodeString; Configurable, Enumerable, Writable: Boolean; Value: JsValueRef); var Descriptor: JsValueRef; PropName: UTF8String; PropId: JsPropertyIdRef; B: ByteBool; begin Descriptor := JsCreateObject; JsSetProperty(Descriptor, 'configurable', BooleanToJsBoolean(Configurable), True); JsSetProperty(Descriptor, 'enumerable', BooleanToJsBoolean(Enumerable), True); JsSetProperty(Descriptor, 'writable', BooleanToJsBoolean(Writable)); JsSetProperty(Descriptor, 'value', Value, True); PropName := UTF8Encode(AName); ChakraCoreCheck(JsCreatePropertyId(PAnsiChar(PropName), Length(PropName), PropId)); ChakraCoreCheck(ChakraCommon.JsDefineProperty(AInstance, PropId, Descriptor, B)); end; class procedure TNativeObject.RegisterProperties(AInstance: JsValueRef); begin // do nothing end; { TNativeObject public } constructor TNativeObject.Create(Args: PJsValueRef; ArgCount: Word; AFinalize: Boolean); const Finalizers: array[Boolean] of JsFinalizeCallback = (nil, Native_FinalizeCallback); var APrototype: JsValueRef; begin inherited Create; FInstance := nil; APrototype := FindPrototype; if Assigned(APrototype) then begin ChakraCoreCheck(JsCreateExternalObjectWithPrototype(Self, Finalizers[AFinalize], APrototype, FInstance)); JsSetExternalData(FInstance, Self); end else begin ChakraCoreCheck(JsCreateExternalObject(Self, Finalizers[AFinalize], FInstance)); JsSetExternalData(FInstance, Self); RegisterMethods(FInstance); RegisterProperties(FInstance); end; InitializeInstance(FInstance, Args, ArgCount); Context.DoNativeObjectCreated(Self); end; constructor TNativeObject.Create(const Args: array of JsValueRef; AFinalize: Boolean); var PArg: PJsValueRef; Len: Integer; begin PArg := nil; Len := Length(Args); if Len > 0 then PArg := @Args[0]; Create(PArg, Len, AFinalize); end; destructor TNativeObject.Destroy; begin // TODO detect context already destroyed if Assigned(FInstance) then ChakraCommon.JsSetExternalData(FInstance, nil); inherited; end; function TNativeObject.AddRef: Integer; begin Result := JsAddRef(FInstance); end; class procedure TNativeObject.Project(const AName: UnicodeString; Scope: JsValueRef; UseStrictRules: Boolean); var ConstructorName: UnicodeString; begin if Self = TNativeObject then // only project descendants Exit; ConstructorName := AName; if ConstructorName = '' then begin ConstructorName := UnicodeString(ClassName); if (ConstructorName[1] = 'T') and (Length(ConstructorName) > 1) then Delete(ConstructorName, 1, 1); end; if not Assigned(Scope) then Scope := JsGlobal; JsDefineProperty(ConstructorName, True, True, JsCreateFunction(Native_GetConstructorCallback, Self, ConstructorName), nil, Scope); end; function TNativeObject.Release: Integer; begin Result := JsRelease(FInstance); end; end. ================================================ FILE: src/ChakraCoreUtils.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit ChakraCoreUtils; {$include common.inc} interface uses Classes, SysUtils, {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Compat, ChakraCommon, ChakraCore; type EChakraCore = class(Exception) ErrorCode: JsErrorCode; Error: JsValueRef; public constructor Create(AErrorCode: JsErrorCode; AError: JsValueRef = nil); end; EChakraCoreEngine = class(EChakraCore); EChakraCoreScript = class(EChakraCore) Line: Integer; Column: Integer; Source: UnicodeString; ScriptURL: UnicodeString; public constructor Create(AErrorCode: JsErrorCode); end; EChakraCoreFatal = class(EChakraCore); EChakraCoreDiag = class(EChakraCore); TErrorType = (etGenericError, etRangeError, etReferenceError, etSyntaxError, etTypeError, etUriError); TJsEnumArrayFunc = function(Value: JsValueRef; Index: Integer; ElementValue: JsValueRef; Data: Pointer): Boolean; TJsEnumPropertyFunc = function(Value: JsValueRef; const PropName: UnicodeString; PropValue: JsValueRef; Data: Pointer): Boolean; PJsValueRefArray = ^TJsValueRefArray; TJsValueRefArray = array[0..255] of JsValueRef; JsValueRefArray = array of JsValueRef; procedure ChakraCoreCheck(ErrorCode: JsErrorCode); procedure RaiseChakraCoreError(ErrorCode: JsErrorCode); procedure RaiseError(Error: JsValueRef); function BooleanToJsBoolean(Value: Boolean): JsValueRef; function DoubleToJsNumber(Value: Double): JsValueRef; function IntToJsNumber(Value: Integer): JsValueRef; function JsFalseValue: JsValueRef; function JsNullValue: JsValueRef; function JsUndefinedValue: JsValueRef; function JsTrueValue: JsValueRef; function StringToJsString(const S: UTF8String): JsValueRef; overload; function StringToJsString(const S: UnicodeString): JsValueRef; overload; function JsEscapeString(const S: UTF8String): UTF8String; overload; function JsEscapeString(const S: UnicodeString): UnicodeString; overload; function JsCreateArray(Length: Integer): JsValueRef; function JsArrayLength(Value: JsValueRef): Integer; function JsArrayGetElement(Value: JsValueRef; Index: Integer): JsValueRef; procedure JsArraySetElement(Value: JsValueRef; Index: Integer; ElementValue: JsValueRef); function StringsToJsArray(const Strings: array of UnicodeString): JsValueRef; overload; function StringsToJsArray(const Strings: array of UTF8String): JsValueRef; overload; function JsBooleanToBoolean(Value: JsValueRef): Boolean; function JsNumberToDouble(Value: JsValueRef): Double; function JsNumberToInt(Value: JsValueRef): Integer; function JsStringToUnicodeString(Value: JsValueRef): UnicodeString; function JsStringToUTF8String(Value: JsValueRef): UTF8String; procedure JsEnumArray(Value: JsValueRef; EnumFunc: TJsEnumArrayFunc; Data: Pointer = nil); procedure JsEnumProperties(Value: JsValueRef; EnumFunc: TJsEnumPropertyFunc; Data: Pointer = nil); function JsInspect(Value: JsValueRef): UnicodeString; function JsInspectArray(Value: JsValueRef): UnicodeString; function JsInspectObject(Value: JsValueRef): UnicodeString; function JsContextOf(Instance: JsValueRef): JsContextRef; function JsGlobal: JsValueRef; function JsGetPrototype(Instance: JsValueRef): JsValueRef; function JsInstanceOf(Instance: JsValueRef; const ConstructorName: UnicodeString; ThisArg: JsValueRef = nil): Boolean; overload; function JsInstanceOf(Instance, AConstructor: JsValueRef): Boolean; overload; function JsNew(const ConstructorName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function JsNew(const ConstructorName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function JsNew(AConstructor, ACallee: JsValueRef; const Args: array of JsValueRef): JsValueRef; overload; function JsAddRef(Value: JsValueRef): Integer; function JsRelease(Value: JsValueRef): Integer; function JsValueAsJsBoolean(Value: JsValueRef): JsValueRef; function JsValueAsJsNumber(Value: JsValueRef): JsValueRef; function JsValueAsJsObject(Value: JsValueRef): JsValueRef; function JsValueAsJsString(Value: JsValueRef): JsValueRef; function JsEqual(Value1, Value2: JsValueRef; AStrict: Boolean = False): Boolean; function JsGetErrorMessage(ErrorCode: JsErrorCode): PResStringRec; function JsCreateObject(APrototype: JsValueRef = nil): JsValueRef; function JsCreateSymbol(const Description: UnicodeString = ''): JsValueRef; function JsCreateNativeTypedArray(AType: JsTypedArrayType; ALength: Integer): JsValueRef; function JsGetExternalData(Value: JsValueRef): Pointer; procedure JsSetExternalData(Value: JsValueRef; Data: Pointer); function JsGetValueType(Value: JsValueRef): JsValueType; function JsGetTypedArrayType(Value: JsValueRef): JsTypedArrayType; function JsCallFunction(Func: JsValueRef; Args: PJsValueRef; ArgCount: Word): JsValueRef; overload; function JsCallFunction(Func: JsValueRef; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function JsCallFunction(const FunctionName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function JsCallFunction(const FunctionName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef = nil): JsValueRef; overload; function JsGetProperty(Value, Prop: JsValueRef): JsValueRef; overload; function JsGetProperty(Value: JsValueRef; PropId: JsPropertyIdRef): JsValueRef; overload; function JsGetProperty(Value: JsValueRef; const PropName: UTF8String): JsValueRef; overload; function JsGetProperty(Value: JsValueRef; const PropName: UnicodeString): JsValueRef; overload; function JsTryGetProperty(Value, Prop: JsValueRef; out PropValue: JsValueRef): Boolean; overload; function JsTryGetProperty(Value: JsValueRef; const PropName: UTF8String; out PropValue: JsValueRef): Boolean; overload; function JsTryGetProperty(Value: JsValueRef; const PropName: UnicodeString; out PropValue: JsValueRef): Boolean; overload; function JsHasException: Boolean; function JsHasExternalData(Value: JsValueRef): Boolean; function JsHasProperty(Value, Prop: JsValueRef): Boolean; overload; function JsHasProperty(Value: JsValueRef; const PropId: JsPropertyIdRef): Boolean; overload; function JsHasProperty(Value: JsValueRef; const PropName: UTF8String): Boolean; overload; function JsHasProperty(Value: JsValueRef; const PropName: UnicodeString): Boolean; overload; function JsCreatePropertyDescriptor(Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; UseStrictRules: Boolean = True): JsValueRef; overload; function JsDefineProperty(PropId: JsPropertyIdRef; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef = nil; UseStrictRules: Boolean = True): Boolean; overload; function JsDefineProperty(const PropName: UTF8String; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef = nil; UseStrictRules: Boolean = True): Boolean; overload; function JsDefineProperty(const PropName: UnicodeString; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef = nil; UseStrictRules: Boolean = True): Boolean; overload; function JsDeleteProperty(Value, Prop: JsValueRef; UseStrictRules: Boolean = True): Boolean; overload; function JsDeleteProperty(Value: JsValueRef; PropId: JsPropertyIdRef; UseStrictRules: Boolean = True): Boolean; overload; function JsDeleteProperty(Value: JsValueRef; const PropName: UTF8String; UseStrictRules: Boolean = True): Boolean; overload; function JsDeleteProperty(Value: JsValueRef; const PropName: UnicodeString; UseStrictRules: Boolean = True): Boolean; overload; function JsParseScript(const Script, Name: UTF8String; SourceContext: NativeUInt = 0; IsLibraryCode: Boolean = False): JsValueRef; overload; function JsParseScript(const Script, Name: UnicodeString; SourceContext: NativeUInt = 0; IsLibraryCode: Boolean = False): JsValueRef; overload; function JsRunScript(const Script, Name: UTF8String; SourceContext: NativeUInt = 0; IsLibraryCode: Boolean = False): JsValueRef; overload; function JsRunScript(const Script, Name: UnicodeString; SourceContext: NativeUInt = 0; IsLibraryCode: Boolean = False): JsValueRef; overload; function JsCreateFunction(Callback: JsNativeFunction; CallbackState: Pointer; const Name: UTF8String = ''): JsValueRef; overload; function JsCreateFunction(Callback: JsNativeFunction; CallbackState: Pointer; const Name: UnicodeString = ''): JsValueRef; overload; procedure JsCreatePromise(out Promise, ResolveFunc, RejectFunc: JsValueRef); function JsSetCallback(Instance: JsValueRef; const CallbackName: UTF8String; Callback: JsNativeFunction; CallbackState: Pointer; UseStrictRules: Boolean = True): JsValueRef; overload; function JsSetCallback(Instance: JsValueRef; const CallbackName: UnicodeString; Callback: JsNativeFunction; CallbackState: Pointer; UseStrictRules: Boolean = True): JsValueRef; overload; procedure JsSetProperty(Instance, Prop, Value: JsValueRef; UseStrictRules: Boolean = True); overload; procedure JsSetProperty(Instance: JsValueRef; PropId: JsPropertyIdRef; Value: JsValueRef; UseStrictRules: Boolean = True); overload; procedure JsSetProperty(Instance: JsValueRef; const PropName: UTF8String; Value: JsValueRef; UseStrictRules: Boolean = True); overload; procedure JsSetProperty(Instance: JsValueRef; const PropName: UnicodeString; Value: JsValueRef; UseStrictRules: Boolean = True); overload; function JsCreateError(const AMessage: UTF8String; ErrorType: TErrorType = etGenericError): JsValueRef; overload; function JsCreateError(const AMessage: UnicodeString; ErrorType: TErrorType = etGenericError): JsValueRef; overload; procedure JsThrowError(const AMessage: UTF8String; ErrorType: TErrorType = etGenericError); overload; procedure JsThrowError(const AMessage: UnicodeString; ErrorType: TErrorType = etGenericError); overload; procedure JsThrowError(Error: JsValueRef); overload; function JsGetCurrentContext: JsContextRef; function JsGetCurrentRuntime: JsRuntimeHandle; function JsIsDebugging: Boolean; type TJsInspectExceptionHandler = function (Value: JsValueRef; E: Exception): UnicodeString; var JsInspectExceptionHandler: TJsInspectExceptionHandler = nil; implementation uses ChakraDebug, ChakraCoreClasses; resourcestring // Category of errors that relates to incorrect usage of the API itself SJsErrorInvalidArgument = 'An argument to a hosting API was invalid'; SJsErrorNullArgument = 'An argument to a hosting API was null in a context where null is not allowed'; SJsErrorNoCurrentContext = 'The hosting API requires that a context be current, but there is no current context'; SJsErrorInExceptionState = 'The engine is in an exception state and no APIs can be called until the exception is cleared'; SJsErrorNotImplemented = 'A hosting API is not yet implemented'; SJsErrorWrongThread = 'A hosting API was called on the wrong thread'; SJsErrorRuntimeInUse = 'A runtime that is still in use cannot be disposed'; SJsErrorBadSerializedScript = 'A bad serialized script was used, or the serialized script was serialized by a different version of the Chakra engine'; SJsErrorInDisabledState = 'The runtime is in a disabled state'; SJsErrorCannotDisableExecution = 'Runtime does not support reliable script interruption'; SJsErrorHeapEnumInProgress = 'A heap enumeration is currently underway in the script context'; SJsErrorArgumentNotObject = 'A hosting API that operates on object values was called with a non-object value'; SJsErrorInProfileCallback = 'A script context is in the middle of a profile callback'; SJsErrorInThreadServiceCallback = 'A thread service callback is currently underway'; SJsErrorCannotSerializeDebugScript = 'Scripts cannot be serialized in debug contexts'; SJsErrorAlreadyDebuggingContext = 'The context cannot be put into a debug state because it is already in a debug state'; SJsErrorAlreadyProfilingContext = 'The context cannot start profiling because it is already profiling'; SJsErrorIdleNotEnabled = 'Idle notification given when the host did not enable idle processing'; SJsCannotSetProjectionEnqueueCallback = 'The context did not accept the enqueue callback'; SJsErrorCannotStartProjection = 'Failed to start projection'; SJsErrorInObjectBeforeCollectCallback = 'The operation is not supported in an object before collect callback'; SJsErrorObjectNotInspectable = 'Object cannot be unwrapped to IInspectable pointer'; SJsErrorPropertyNotSymbol = 'A hosting API that operates on symbol property ids but was called with a non-symbol property id'; SJsErrorPropertyNotString = 'A hosting API that operates on string property ids but was called with a non-string property id'; SJsErrorInvalidContext = 'Module evaulation is called in wrong context'; SJsInvalidModuleHostInfoKind = 'Invalid module host info kind'; SJsErrorModuleParsed = 'Module was parsed already when JsParseModuleSource is called'; SJsErrorModuleEvaluated = 'Module was evaluated already when JsModuleEvaluation is called'; SJsNoWeakRefRequired = 'Argument passed to JsCreateWeakReference is a primitive that is not managed by the GC. No weak reference is required, the value will never be collected.'; SJsErrorPromisePending = 'The Promise object is still in the pending state.'; SJsErrorModuleNotEvaluated = 'Module was not yet evaluated when JsGetModuleNamespace was called.'; // Category of errors that relates to errors occurring within the engine itself SJsErrorOutOfMemory = 'The Chakra engine has run out of memory'; SJsErrorBadFPUState = 'The Chakra engine failed to set the Floating Point Unit state'; // Category of errors that relates to errors in a script SJsErrorScriptException = 'A JavaScript exception occurred while running a script'; SJsErrorScriptCompile = 'JavaScript failed to compile'; SJsErrorScriptTerminated = 'A script was terminated due to a request to suspend a runtime'; SJsErrorScriptEvalDisabled = 'A script was terminated because it tried to use eval or function and eval was disabled'; // Category of errors that are fatal and signify failure of the engine SJsErrorFatal = 'A fatal error in the engine has occurred'; SJsErrorWrongRuntime = 'A hosting API was called with object created on different javascript runtime'; // Category of errors that are related to failures during diagnostic operations SJsErrorDiagAlreadyInDebugMode = 'The object for which the debugging API was called was not found'; SJsErrorDiagNotInDebugMode = 'The debugging API can only be called when VM is in debug mode'; SJsErrorDiagNotAtBreak = 'The debugging API can only be called when VM is at a break'; SJsErrorDiagInvalidHandle = 'Debugging API was called with an invalid handle'; SJsErrorDiagObjectNotFound = 'The object for which the debugging API was called was not found'; SJsErrorDiagUnableToPerformAction = 'VM was unable to perfom the request action'; type JsErrorConstructor = function(_message: JsValueRef; out error: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} { EChakra public } constructor EChakraCore.Create(AErrorCode: JsErrorCode; AError: JsValueRef); begin inherited CreateRes(JsGetErrorMessage(AErrorCode)); ErrorCode := AErrorCode; Error := AError; if not Assigned(Error) then JsGetAndClearException(Error); end; { EChakraCoreScript public } constructor EChakraCoreScript.Create(AErrorCode: JsErrorCode); var PropValue, MetaData: JsValueRef; SException: UnicodeString; begin SException := ''; if JsGetAndClearExceptionWithMetadata(MetaData) = JsNoError then begin Line := JsNumberToInt(JsGetProperty(MetaData, 'line')); Column := JsNumberToInt(JsGetProperty(MetaData, 'column')); Source := JsStringToUnicodeString(JsGetProperty(MetaData, 'source')); ScriptURL := JsStringToUnicodeString(JsGetProperty(MetaData, 'url')); Error := JsGetProperty(MetaData, 'exception'); end else if JsGetAndClearException(Error) = JsNoError then begin if JsTryGetProperty(Error, 'line', PropValue) and (JsGetValueType(PropValue) = JsNumber) then Line := JsNumberToInt(PropValue); if JsTryGetProperty(Error, 'column', PropValue) and (JsGetValueType(PropValue) = JsNumber) then Column := JsNumberToInt(PropValue); if JsTryGetProperty(Error, 'source', PropValue) and (JsGetValueType(PropValue) = JsString) then Source := JsStringToUnicodeString(PropValue); if JsTryGetProperty(Error, 'url', PropValue) and (JsGetValueType(PropValue) = JsString) then ScriptURL := JsStringToUnicodeString(PropValue); end; inherited Create(AErrorCode, Error); if Assigned(Error) then SException := JsStringToUnicodeString(Error); if SException <> '' then {$ifdef UNICODE} Message := Message + sLineBreak + SException; {$else} Message := Message + sLineBreak + UTF8Encode(SException); {$endif} end; function BooleanToJsBoolean(Value: Boolean): JsValueRef; begin ChakraCoreCheck(JsBoolToBoolean(Value, Result)); end; procedure ChakraCoreCheck(ErrorCode: JsErrorCode); begin if ErrorCode <> JsNoError then RaiseChakraCoreError(ErrorCode); end; procedure RaiseChakraCoreError(ErrorCode: JsErrorCode); begin case JsErrorCode(Ord(ErrorCode) and $F0000) of // JsErrorCategoryUsage: ; JsErrorCategoryEngine: raise EChakraCoreEngine.Create(ErrorCode); JsErrorCategoryScript: raise EChakraCoreScript.Create(ErrorCode); JsErrorCategoryFatal: raise EChakraCoreFatal.Create(ErrorCode); JsErrorCategoryDiagError: raise EChakraCoreDiag.Create(ErrorCode); else raise EChakraCore.Create(ErrorCode); end; end; procedure RaiseError(Error: JsValueRef); begin if not Assigned(Error) then Exit; {$ifdef UNICODE} raise Exception.Create(JsInspect(Error)); {$else} raise Exception.Create(UTF8Encode(JsInspect(Error))); {$endif} end; function DoubleToJsNumber(Value: Double): JsValueRef; begin ChakraCoreCheck(JsDoubleToNumber(Value, Result)); end; function IntToJsNumber(Value: Integer): JsValueRef; begin ChakraCoreCheck(JsIntToNumber(Value, Result)); end; function JsFalseValue: JsValueRef; begin ChakraCoreCheck(JsGetFalseValue(Result)); end; function JsNullValue: JsValueRef; begin ChakraCoreCheck(JsGetNullValue(Result)); end; function JsUndefinedValue: JsValueRef; begin ChakraCoreCheck(JsGetUndefinedValue(Result)); end; function JsTrueValue: JsValueRef; begin ChakraCoreCheck(JsGetTrueValue(Result)); end; function StringToJsString(const S: UTF8String): JsValueRef; begin ChakraCoreCheck(JsCreateString(PAnsiChar(S), Length(S), Result)); end; function StringToJsString(const S: UnicodeString): JsValueRef; const Null: UnicodeChar = #0; PNull: PUnicodeChar = @Null; var P: PUnicodeChar; begin P := PUnicodeChar(S); if not Assigned(P) then P := PNull; ChakraCoreCheck(JsCreateStringUtf16(P, Length(S), Result)); end; function JsEscapeString(const S: UTF8String): UTF8String; begin Result := UTF8Encode(JsEscapeString(UTF8ToString(S))); end; // TODO see https://mathiasbynens.be/notes/javascript-escapes function JsEscapeString(const S: UnicodeString): UnicodeString; begin Result := S; Result := WideStringReplace(Result, '\', '\\', [rfReplaceAll]); Result := WideStringReplace(Result, #8, '\b', [rfReplaceAll]); Result := WideStringReplace(Result, #9, '\t', [rfReplaceAll]); Result := WideStringReplace(Result, #10, '\n', [rfReplaceAll]); Result := WideStringReplace(Result, #11, '\v', [rfReplaceAll]); Result := WideStringReplace(Result, #12, '\f', [rfReplaceAll]); Result := WideStringReplace(Result, #13, '\r', [rfReplaceAll]); Result := WideStringReplace(Result, '"', '\"', [rfReplaceAll]); Result := WideStringReplace(Result, '''', '\''', [rfReplaceAll]); end; function JsCreateArray(Length: Integer): JsValueRef; begin ChakraCoreCheck(ChakraCommon.JsCreateArray(Length, Result)); end; function JsArrayLength(Value: JsValueRef): Integer; begin Result := JsNumberToInt(JsGetProperty(Value, 'length')); end; function JsArrayGetElement(Value: JsValueRef; Index: Integer): JsValueRef; begin ChakraCoreCheck(JsGetIndexedProperty(Value, IntToJsNumber(Index), Result)); end; procedure JsArraySetElement(Value: JsValueRef; Index: Integer; ElementValue: JsValueRef); begin ChakraCoreCheck(JsSetIndexedProperty(Value, IntToJsNumber(Index), ElementValue)); end; function StringsToJsArray(const Strings: array of UnicodeString): JsValueRef; var L, I: Integer; begin L := Length(Strings); Result := JsCreateArray(L); for I := 0 to L - 1 do JsArraySetElement(Result, I, StringToJsString(Strings[I])); end; function StringsToJsArray(const Strings: array of UTF8String): JsValueRef; var L, I: Integer; begin L := Length(Strings); Result := JsCreateArray(L); for I := 0 to L - 1 do JsArraySetElement(Result, I, StringToJsString(Strings[I])); end; function JsBooleanToBoolean(Value: JsValueRef): Boolean; var B: ByteBool; begin ChakraCoreCheck(JsBooleanToBool(Value, B)); Result := B; end; function JsNumberToDouble(Value: JsValueRef): Double; begin Result := -1; ChakraCoreCheck(ChakraCommon.JsNumberToDouble(Value, Result)); end; function JsNumberToInt(Value: JsValueRef): Integer; begin Result := -1; ChakraCoreCheck(ChakraCommon.JsNumberToInt(Value, Result)); end; function JsStringToUnicodeString(Value: JsValueRef): UnicodeString; var StringValue: JsValueRef; StringLength: size_t; begin Result := ''; StringValue := JsValueAsJsString(Value); StringLength := 0; ChakraCoreCheck(JsCopyStringUtf16(StringValue, 0, -1, nil, @StringLength)); if StringLength > 0 then begin SetLength(Result, StringLength); ChakraCoreCheck(JsCopyStringUtf16(StringValue, 0, StringLength, PUnicodeChar(Result), nil)); end; end; function JsStringToUTF8String(Value: JsValueRef): UTF8String; var StringValue: JsValueRef; StringLength: size_t; begin Result := ''; StringValue := JsValueAsJsString(Value); StringLength := 0; ChakraCoreCheck(JsCopyString(StringValue, nil, 0, @StringLength)); if StringLength > 0 then begin SetLength(Result, StringLength); ChakraCoreCheck(JsCopyString(StringValue, PAnsiChar(Result), StringLength, nil)); end; end; procedure JsEnumArray(Value: JsValueRef; EnumFunc: TJsEnumArrayFunc; Data: Pointer); var I: Integer; ElementValue: JsValueRef; begin if JsGetValueType(Value) <> JsArray then Exit; for I := 0 to JsArrayLength(Value) - 1 do begin ElementValue := JsArrayGetElement(Value, I); if EnumFunc(Value, I, ElementValue, Data) then Break; end; end; type PListPropData = ^TListPropData; TListPropData = record Instance: JsValueRef; EnumFunc: TJsEnumPropertyFunc; Data: Pointer; end; function _EnumPropertyFunc(Value: JsValueRef; Index: Integer; ElementValue: JsValueRef; Data: Pointer): Boolean; var ListPropData: PListPropData absolute Data; PropName: UnicodeString; begin Result := False; PropName := JsStringToUnicodeString(ElementValue); ListPropData^.EnumFunc(ListPropData^.Instance, PropName, JsGetProperty(ListPropData^.Instance, PropName), ListPropData^.Data); end; procedure JsEnumProperties(Value: JsValueRef; EnumFunc: TJsEnumPropertyFunc; Data: Pointer); var PropNames: JsValueRef; ListPropData: TListPropData; begin ChakraCoreCheck(JsGetOwnPropertyNames(Value, PropNames)); if JsGetValuetype(PropNames) = JsArray then begin ListPropData.Instance := Value; ListPropData.EnumFunc := EnumFunc; ListPropData.Data := Data; JsEnumArray(PropNames, _EnumPropertyFunc, @ListPropData); end; end; function JsInspect(Value: JsValueRef): UnicodeString; begin Result := ''; try case JsGetValueType(Value) of JsObject: Result := '{' + JsInspectObject(Value) + '}'; JsArray: Result := '[' + JsInspectArray(Value) + ']'; JsArrayBuffer: Result := '{' + JsInspectObject(Value) + '}'; JsTypedArray: Result := '{' + JsInspectObject(Value) + '}'; JsDataView: Result := '{' + JsInspectObject(Value) + '}'; else Result := '"' + JsEscapeString(JsStringToUnicodeString(JsValueAsJsString(Value))) + '"'; end; except on E: Exception do begin if not Assigned(JsInspectExceptionHandler) then raise; Result := Result + '"' + JsEscapeString(JsInspectExceptionHandler(Value, E)) + '"'; end; end; end; function _JsInspectArrayElement(Value: JsValueRef; Index: Integer; ElementValue: JsValueRef; Data: Pointer): Boolean; var S: PUnicodeString absolute Data; begin Result := False; if Index > 0 then S^ := S^ + ','; S^ := S^ + JsInspect(ElementValue); end; function JsInspectArray(Value: JsValueRef): UnicodeString; begin Result := ''; JsEnumArray(Value, _JsInspectArrayElement, @Result); end; function _JsInspectObjectProperty(Instance: JsValueRef; const PropName: UnicodeString; PropValue: JsValueRef; Data: Pointer): Boolean; var S: PUnicodeString absolute data; begin Result := False; if S^ <> '' then S^ := S^ + ','; S^ := S^ + '"' + PropName + '":' + JsInspect(PropValue); end; function JsInspectObject(Value: JsValueRef): UnicodeString; begin Result := ''; JsEnumProperties(Value, _JsInspectObjectProperty, @Result); end; function JsContextOf(Instance: JsValueRef): JsContextRef; begin ChakraCoreCheck(JsGetContextOfObject(Instance, Result)); end; function JsGlobal: JsValueRef; begin ChakraCoreCheck(JsGetGlobalObject(Result)); end; function JsGetPrototype(Instance: JsValueRef): JsValueRef; begin ChakraCoreCheck(ChakraCommon.JsGetPrototype(Instance, Result)); end; function JsInstanceOf(Instance: JsValueRef; const ConstructorName: UnicodeString; ThisArg: JsValueRef): Boolean; begin if not Assigned(ThisArg) then ThisArg := JsGlobal; Result := JsInstanceOf(Instance, JsGetProperty(ThisArg, ConstructorName)); end; function JsInstanceOf(Instance, AConstructor: JsValueRef): Boolean; var B: ByteBool; begin ChakraCoreCheck(ChakraCommon.JsInstanceOf(Instance, AConstructor, B)); Result := B; end; function JsNew(const ConstructorName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; var AConstructor: JsValueRef; begin if not Assigned(ThisArg) then ThisArg := JsGlobal; AConstructor := JsGetProperty(ThisArg, ConstructorName); Result := JsNew(AConstructor, AConstructor, Args); end; function JsNew(const ConstructorName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; var AConstructor: JsValueRef; begin if not Assigned(ThisArg) then ThisArg := JsGlobal; AConstructor := JsGetProperty(ThisArg, ConstructorName); Result := JsNew(AConstructor, AConstructor, Args); end; function JsNew(AConstructor, ACallee: JsValueRef; const Args: array of JsValueRef): JsValueRef; var NewArgs: JsValueRefArray; L: Integer; begin // pass callee + args L := Length(Args); SetLength(NewArgs, L + 1); NewArgs[0] := ACallee; Move(Args[0], NewArgs[1], L * SizeOf(JsValueRef)); ChakraCoreCheck(ChakraCommon.JsConstructObject(AConstructor, @NewArgs[0], L + 1, Result)); end; function JsAddRef(Value: JsValueRef): Integer; begin ChakraCoreCheck(ChakraCommon.JsAddRef(Value, @Result)); end; function JsRelease(Value: JsValueRef): Integer; begin ChakraCoreCheck(ChakraCommon.JsRelease(Value, @Result)); end; function JsValueAsJsBoolean(Value: JsValueRef): JsValueRef; begin ChakraCoreCheck(JsConvertValueToBoolean(Value, Result)); end; function JsValueAsJsNumber(Value: JsValueRef): JsValueRef; begin ChakraCoreCheck(JsConvertValueToNumber(Value, Result)); end; function JsValueAsJsObject(Value: JsValueRef): JsValueRef; begin ChakraCoreCheck(JsConvertValueToObject(Value, Result)); end; function JsValueAsJsString(Value: JsValueRef): JsValueRef; begin ChakraCoreCheck(JsConvertValueToString(Value, Result)); end; function JsEqual(Value1, Value2: JsValueRef; AStrict: Boolean): Boolean; var B: ByteBool; begin if AStrict then ChakraCoreCheck(JsStrictEquals(Value1, Value2, B)) else ChakraCoreCheck(JsEquals(Value1, Value2, B)); Result := B; end; function JsGetErrorMessage(ErrorCode: JsErrorCode): PResStringRec; begin case ErrorCode of // JsNoError // JsErrorCategoryUsage JsErrorInvalidArgument: Result := @SJsErrorInvalidArgument; JsErrorNullArgument: Result := @SJsErrorNullArgument; JsErrorNoCurrentContext: Result := @SJsErrorNoCurrentContext; JsErrorInExceptionState: Result := @SJsErrorInExceptionState; JsErrorNotImplemented: Result := @SJsErrorNotImplemented; JsErrorWrongThread: Result := @SJsErrorWrongThread; JsErrorRuntimeInUse: Result := @SJsErrorRuntimeInUse; JsErrorBadSerializedScript: Result := @SJsErrorBadSerializedScript; JsErrorInDisabledState: Result := @SJsErrorInDisabledState; JsErrorCannotDisableExecution: Result := @SJsErrorCannotDisableExecution; JsErrorHeapEnumInProgress: Result := @SJsErrorHeapEnumInProgress; JsErrorArgumentNotObject: Result := @SJsErrorArgumentNotObject; JsErrorInProfileCallback: Result := @SJsErrorInProfileCallback; JsErrorInThreadServiceCallback: Result := @SJsErrorInThreadServiceCallback; JsErrorCannotSerializeDebugScript: Result := @SJsErrorCannotSerializeDebugScript; JsErrorAlreadyDebuggingContext: Result := @SJsErrorAlreadyDebuggingContext; JsErrorAlreadyProfilingContext: Result := @SJsErrorAlreadyProfilingContext; JsErrorIdleNotEnabled: Result := @SJsErrorIdleNotEnabled; JsCannotSetProjectionEnqueueCallback: Result := @SJsCannotSetProjectionEnqueueCallback; JsErrorCannotStartProjection: Result := @SJsErrorCannotStartProjection; JsErrorInObjectBeforeCollectCallback: Result := @SJsErrorInObjectBeforeCollectCallback; JsErrorObjectNotInspectable: Result := @SJsErrorObjectNotInspectable; JsErrorPropertyNotSymbol: Result := @SJsErrorPropertyNotSymbol; JsErrorPropertyNotString: Result := @SJsErrorPropertyNotString; JsErrorInvalidContext: Result := @SJsErrorInvalidContext; JsInvalidModuleHostInfoKind: Result := @SJsInvalidModuleHostInfoKind; JsErrorModuleParsed: Result := @SJsErrorModuleParsed; JsErrorModuleEvaluated: Result := @SJsErrorModuleEvaluated; JsNoWeakRefRequired: Result := @SJsNoWeakRefRequired; JsErrorPromisePending: Result := @SJsErrorPromisePending; JsErrorModuleNotEvaluated: Result := @SJsErrorModuleNotEvaluated; // JsErrorCategoryEngine JsErrorOutOfMemory: Result := @SJsErrorOutOfMemory; JsErrorBadFPUState: Result := @SJsErrorBadFPUState; // JsErrorCategoryScript JsErrorScriptException: Result := @SJsErrorScriptException; JsErrorScriptCompile: Result := @SJsErrorScriptCompile; JsErrorScriptTerminated: Result := @SJsErrorScriptTerminated; JsErrorScriptEvalDisabled: Result := @SJsErrorScriptEvalDisabled; // JsErrorCategoryFatal JsErrorFatal: Result := @SJsErrorFatal; JsErrorWrongRuntime: Result := @SJsErrorWrongRuntime; // JsErrorCategoryDiagError JsErrorDiagAlreadyInDebugMode: Result := @SJsErrorDiagAlreadyInDebugMode; JsErrorDiagNotInDebugMode: Result := @SJsErrorDiagNotInDebugMode; JsErrorDiagNotAtBreak: Result := @SJsErrorDiagNotAtBreak; JsErrorDiagInvalidHandle: Result := @SJsErrorDiagInvalidHandle; JsErrorDiagObjectNotFound: Result := @SJsErrorDiagObjectNotFound; JsErrorDiagUnableToPerformAction: Result := @SJsErrorDiagUnableToPerformAction; else Result := nil; end; end; function JsCreateObject(APrototype: JsValueRef): JsValueRef; begin if Assigned(APrototype) then // Object.create(prototype) Result := JsCallFunction('create', [APrototype], JsGetProperty(JsGlobal, 'Object')) else ChakraCoreCheck(ChakraCommon.JsCreateObject(Result)); end; function JsCreateSymbol(const Description: UnicodeString): JsValueRef; var Desc: JsValueRef; begin Desc := JsNullValue; if Description <> '' then Desc := StringToJsString(Description); ChakraCoreCheck(ChakraCommon.JsCreateSymbol(Desc, Result)); end; function JsCreateNativeTypedArray(AType: JsTypedArrayType; ALength: Integer): JsValueRef; const ElementSizes: array[JsTypedArrayType] of Integer = (8, 8, 8, 16, 16, 32, 32, 32, 64); var Base: TChakraCoreNativeArrayBuffer; begin Base := TChakraCoreNativeArrayBuffer.Create(ALength * ElementSizes[AType]); try ChakraCoreCheck(JsCreateTypedArray(AType, Base.Handle, 0, ALength, Result)); except Base.Free; raise; end; end; function JsGetExternalData(Value: JsValueRef): Pointer; begin ChakraCoreCheck(ChakraCommon.JsGetExternalData(Value, Result)); end; procedure JsSetExternalData(Value: JsValueRef; Data: Pointer); begin ChakraCoreCheck(ChakraCommon.JsSetExternalData(Value, Data)); end; function JsGetValueType(Value: JsValueRef): JsValueType; begin ChakraCoreCheck(ChakraCommon.JsGetValueType(Value, Result)); end; function JsGetTypedArrayType(Value: JsValueRef): JsTypedArrayType; begin ChakraCoreCheck(JsGetTypedArrayInfo(Value, @Result, nil, nil, nil)); end; function JsCallFunction(Func: JsValueRef; Args: PJsValueRef; ArgCount: Word): JsValueRef; begin ChakraCoreCheck(ChakraCommon.JsCallFunction(Func, Args, ArgCount, @Result)); end; function JsCallFunction(Func: JsValueRef; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; var L: Integer; NewArgs: array of JsValueRef; begin if not Assigned(ThisArg) then ThisArg := JsGlobal; L := Length(Args); SetLength(NewArgs, L + 1); NewArgs[0] := ThisArg; if L > 0 then Move(Args[0], NewArgs[1], L * SizeOf(JsValueRef)); Result := JsCallFunction(Func, @NewArgs[0], L + 1); end; function JsCallFunction(const FunctionName: UTF8String; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; var Func: JsValueRef; begin if not Assigned(ThisArg) then ThisArg := JsGlobal; Func := JsGetProperty(ThisArg, FunctionName); Result := JsCallFunction(Func, Args, ThisArg); end; function JsCallFunction(const FunctionName: UnicodeString; const Args: array of JsValueRef; ThisArg: JsValueRef): JsValueRef; begin Result := JsCallFunction(UTF8Encode(FunctionName), Args, ThisArg); end; function JsGetProperty(Value, Prop: JsValueRef): JsValueRef; begin ChakraCoreCheck(JsObjectGetProperty(Value, Prop, Result)); end; function JsGetProperty(Value: JsValueRef; PropId: JsPropertyIdRef): JsValueRef; begin ChakraCoreCheck(ChakraCommon.JsGetProperty(Value, PropId, Result)); end; function JsGetProperty(Value: JsValueRef; const PropName: UTF8String): JsValueRef; begin ChakraCoreCheck(JsObjectGetProperty(Value, StringToJsString(PropName), Result)); end; function JsGetProperty(Value: JsValueRef; const PropName: UnicodeString): JsValueRef; begin ChakraCoreCheck(JsObjectGetProperty(Value, StringToJsString(PropName), Result)); end; function JsTryGetProperty(Value, Prop: JsValueRef; out PropValue: JsValueRef): Boolean; begin Result := JsObjectGetProperty(Value, Prop, PropValue) = JsNoError; end; function JsTryGetProperty(Value: JsValueRef; const PropName: UTF8String; out PropValue: JsValueRef): Boolean; begin Result := JsObjectGetProperty(Value, StringToJsString(PropName), PropValue) = JsNoError; end; function JsTryGetProperty(Value: JsValueRef; const PropName: UnicodeString; out PropValue: JsValueRef): Boolean; begin Result := JsObjectGetProperty(Value, StringToJsString(PropName), PropValue) = JsNoError; end; function JsHasException: Boolean; var B: ByteBool; begin ChakraCoreCheck(ChakraCommon.JsHasException(B)); Result := B; end; function JsHasExternalData(Value: JsValueRef): Boolean; var B: ByteBool; begin ChakraCoreCheck(ChakraCommon.JsHasExternalData(Value, B)); Result := B; end; function JsHasProperty(Value, Prop: JsValueRef): Boolean; var B: ByteBool; begin ChakraCoreCheck(JsObjectHasProperty(Value, Prop, B)); Result := B; end; function JsHasProperty(Value: JsValueRef; const PropId: JsPropertyIdRef): Boolean; var B: ByteBool; begin ChakraCoreCheck(ChakraCore.JsHasOwnProperty(Value, PropId, B)); Result := B; end; function JsHasProperty(Value: JsValueRef; const PropName: UTF8String): Boolean; var B: ByteBool; begin ChakraCoreCheck(JsObjectHasProperty(Value, StringToJsString(PropName), B)); Result := B; end; function JsHasProperty(Value: JsValueRef; const PropName: UnicodeString): Boolean; var B: ByteBool; begin ChakraCoreCheck(JsObjectHasProperty(Value, StringToJsString(PropName), B)); Result := B; end; function JsCreatePropertyDescriptor(Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; UseStrictRules: Boolean): JsValueRef; begin Result := JsCreateObject; JsSetProperty(Result, 'configurable', BooleanToJsBoolean(Configurable), True); JsSetProperty(Result, 'enumerable', BooleanToJsBoolean(Enumerable), True); if Assigned(GetAccessor) and (JsGetValueType(GetAccessor) = JsFunction) then JsSetProperty(Result, 'get', GetAccessor, UseStrictRules); if Assigned(SetAccessor) and (JsGetValueType(SetAccessor) = JsFunction) then JsSetProperty(Result, 'set', SetAccessor, UseStrictRules); end; function JsDefineProperty(PropId: JsPropertyIdRef; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef; UseStrictRules: Boolean): Boolean; begin if not Assigned(Scope) then Scope := JsGlobal; ChakraCoreCheck(ChakraCommon.JsDefineProperty(Scope, PropId, JsCreatePropertyDescriptor(Configurable, Enumerable, GetAccessor, SetAccessor, UseStrictRules), ByteBool(Result))); end; function JsDefineProperty(const PropName: UTF8String; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef; UseStrictRules: Boolean): Boolean; var PropId: JsPropertyIdRef; begin ChakraCoreCheck(JsCreatePropertyId(PAnsiChar(PropName), Length(PropName), PropId)); Result := JsDefineProperty(PropId, Configurable, Enumerable, GetAccessor, SetAccessor, Scope, UseStrictRules); end; function JsDefineProperty(const PropName: UnicodeString; Configurable, Enumerable: Boolean; GetAccessor, SetAccessor: JsValueRef; Scope: JsValueRef; UseStrictRules: Boolean): Boolean; begin Result := JsDefineProperty(UTF8Encode(PropName), Configurable, Enumerable, GetAccessor, SetAccessor, Scope, UseStrictRules); end; function JsDeleteProperty(Value, Prop: JsValueRef; UseStrictRules: Boolean): Boolean; var B: JsValueRef; begin ChakraCoreCheck(JsObjectDeleteProperty(Value, Prop, UseStrictRules, B)); Result := JsBooleanToBoolean(JsValueAsJsBoolean(B)); end; function JsDeleteProperty(Value: JsValueRef; PropId: JsPropertyIdRef; UseStrictRules: Boolean): Boolean; var B: JsValueRef; begin ChakraCoreCheck(ChakraCommon.JsDeleteProperty(Value, PropId, UseStrictRules, B)); Result := JsBooleanToBoolean(JsValueAsJsBoolean(B)); end; function JsDeleteProperty(Value: JsValueRef; const PropName: UTF8String; UseStrictRules: Boolean): Boolean; var B: JsValueRef; begin ChakraCoreCheck(JsObjectDeleteProperty(Value, StringToJsString(PropName), UseStrictRules, B)); Result := JsBooleanToBoolean(JsValueAsJsBoolean(B)); end; function JsDeleteProperty(Value: JsValueRef; const PropName: UnicodeString; UseStrictRules: Boolean): Boolean; var B: JsValueRef; begin ChakraCoreCheck(JsObjectDeleteProperty(Value, StringToJsString(PropName), UseStrictRules, B)); Result := JsBooleanToBoolean(JsValueAsJsBoolean(B)); end; function JsParseScript(const Script, Name: UTF8String; SourceContext: NativeUInt; IsLibraryCode: Boolean): JsValueRef; const ParseScriptAttributes: array[Boolean] of JsParseScriptAttributes = ([], [JsParseScriptAttributeLibraryCode]); var ScriptName, ScriptSource: JsValueRef; begin ScriptName := StringToJsString(Name); ChakraCoreCheck(JsCreateExternalArrayBuffer(Pointer(Script), Length(Script), nil, nil, ScriptSource)); ChakraCoreCheck(JsParse(ScriptSource, SourceContext, ScriptName, ParseScriptAttributes[IsLibraryCode], Result)); end; function JsParseScript(const Script, Name: UnicodeString; SourceContext: NativeUInt; IsLibraryCode: Boolean): JsValueRef; const ParseScriptAttributes: array[Boolean] of JsParseScriptAttributes = ([JsParseScriptAttributeArrayBufferIsUtf16Encoded], [JsParseScriptAttributeLibraryCode, JsParseScriptAttributeArrayBufferIsUtf16Encoded]); var ScriptName, ScriptSource: JsValueRef; begin ScriptName := StringToJsString(Name); ChakraCoreCheck(JsCreateExternalArrayBuffer(Pointer(PUnicodeChar(Script)), Length(Script) * SizeOf(UnicodeChar), nil, nil, ScriptSource)); ChakraCoreCheck(JsParse(ScriptSource, SourceContext, ScriptName, ParseScriptAttributes[IsLibraryCode], Result)); end; function JsRunScript(const Script, Name: UTF8String; SourceContext: NativeUInt; IsLibraryCode: Boolean): JsValueRef; const ParseScriptAttributes: array[Boolean] of JsParseScriptAttributes = ([], [JsParseScriptAttributeLibraryCode]); var ScriptName, ScriptSource: JsValueRef; begin ScriptName := StringToJsString(Name); ChakraCoreCheck(JsCreateExternalArrayBuffer(Pointer(Script), Length(Script), nil, nil, ScriptSource)); ChakraCoreCheck(JsRun(ScriptSource, SourceContext, ScriptName, ParseScriptAttributes[IsLibraryCode], Result)); end; function JsRunScript(const Script, Name: UnicodeString; SourceContext: NativeUInt; IsLibraryCode: Boolean): JsValueRef; const ParseScriptAttributes: array[Boolean] of JsParseScriptAttributes = ([JsParseScriptAttributeArrayBufferIsUtf16Encoded], [JsParseScriptAttributeLibraryCode, JsParseScriptAttributeArrayBufferIsUtf16Encoded]); var ScriptName, ScriptSource: JsValueRef; begin ScriptName := StringToJsString(Name); ChakraCoreCheck(JsCreateExternalArrayBuffer(Pointer(PUnicodeChar(Script)), Length(Script) * SizeOf(UnicodeChar), nil, nil, ScriptSource)); ChakraCoreCheck(JsRun(ScriptSource, SourceContext, ScriptName, ParseScriptAttributes[IsLibraryCode], Result)); end; function JsCreateFunction(Callback: JsNativeFunction; CallbackState: Pointer; const Name: UTF8String): JsValueRef; begin if Name = '' then ChakraCoreCheck(ChakraCommon.JsCreateFunction(Callback, CallbackState, Result)) else ChakraCoreCheck(ChakraCommon.JsCreateNamedFunction(StringToJsString(Name), Callback, CallbackState, Result)); end; function JsCreateFunction(Callback: JsNativeFunction; CallbackState: Pointer; const Name: UnicodeString): JsValueRef; begin if Name = '' then ChakraCoreCheck(ChakraCommon.JsCreateFunction(Callback, CallbackState, Result)) else ChakraCoreCheck(ChakraCommon.JsCreateNamedFunction(StringToJsString(Name), Callback, CallbackState, Result)); end; procedure JsCreatePromise(out Promise, ResolveFunc, RejectFunc: JsValueRef); begin ChakraCoreCheck(ChakraCore.JsCreatePromise(Promise, ResolveFunc, RejectFunc)); end; function JsSetCallback(Instance: JsValueRef; const CallbackName: UTF8String; Callback: JsNativeFunction; CallbackState: Pointer; UseStrictRules: Boolean): JsValueRef; begin Result := JsCreateFunction(Callback, CallbackState, CallbackName); JsSetProperty(Instance, CallbackName, Result, UseStrictRules); end; function JsSetCallback(Instance: JsValueRef; const CallbackName: UnicodeString; Callback: JsNativeFunction; CallbackState: Pointer; UseStrictRules: Boolean): JsValueRef; begin Result := JsSetCallback(Instance, UTF8Encode(CallbackName), Callback, CallbackState, UseStrictRules); end; procedure JsSetProperty(Instance, Prop, Value: JsValueRef; UseStrictRules: Boolean); begin ChakraCoreCheck(JsObjectSetProperty(Instance, Prop, Value, UseStrictRules)); end; procedure JsSetProperty(Instance: JsValueRef; PropId: JsPropertyIdRef; Value: JsValueRef; UseStrictRules: Boolean); begin ChakraCoreCheck(ChakraCommon.JsSetProperty(Instance, PropId, Value, UseStrictRules)); end; procedure JsSetProperty(Instance: JsValueRef; const PropName: UTF8String; Value: JsValueRef; UseStrictRules: Boolean); begin ChakraCoreCheck(JsObjectSetProperty(Instance, StringToJsString(PropName), Value, UseStrictRules)); end; procedure JsSetProperty(Instance: JsValueRef; const PropName: UnicodeString; Value: JsValueRef; UseStrictRules: Boolean); begin ChakraCoreCheck(JsObjectSetProperty(Instance, StringToJsString(PropName), Value, UseStrictRules)); end; const ChakraCoreErrorConstructors: array[TErrorType] of JsErrorConstructor = ( ChakraCommon.JsCreateError, JsCreateRangeError, JsCreateReferenceError, JsCreateSyntaxError, JsCreateTypeError, JsCreateUriError ); function JsCreateError(const AMessage: UTF8String; ErrorType: TErrorType = etGenericError): JsValueRef; begin ChakraCoreCheck(ChakraCoreErrorConstructors[ErrorType](StringToJsString(AMessage), Result)); end; function JsCreateError(const AMessage: UnicodeString; ErrorType: TErrorType = etGenericError): JsValueRef; begin ChakraCoreCheck(ChakraCoreErrorConstructors[ErrorType](StringToJsString(AMessage), Result)); end; procedure JsThrowError(const AMessage: UTF8String; ErrorType: TErrorType = etGenericError); begin JsThrowError(JsCreateError(AMessage, ErrorType)); end; procedure JsThrowError(const AMessage: UnicodeString; ErrorType: TErrorType); begin JsThrowError(JsCreateError(AMessage, ErrorType)); end; procedure JsThrowError(Error: JsValueRef); begin ChakraCoreCheck(JsSetException(Error)); end; function JsGetCurrentContext: JsContextRef; begin ChakraCoreCheck(ChakraCommon.JsGetCurrentContext(Result)); end; function JsGetCurrentRuntime: JsRuntimeHandle; begin ChakraCoreCheck(ChakraCommon.JsGetRuntime(JsGetCurrentContext, Result)); end; function JsIsDebugging: Boolean; var DiagAttributes: JsDiagBreakOnExceptionAttributes; begin Result := JsDiagGetBreakOnException(JsGetCurrentRuntime, DiagAttributes) <> JsErrorDiagNotInDebugMode; end; end. ================================================ FILE: src/ChakraCoreVersion.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- // NOTE: When changing this file, you may need to update the GUID in ByteCodeCacheReleaseFileVersion.h // Please update the GUID when: // * CHAKRA_CORE_VERSION_RELEASE is changed to 1 // * CHAKRA_CORE_VERSION_RELEASE is currently set to 1 and the bytecode changes // See notes below about ReleaseVersioningScheme. unit ChakraCoreVersion; interface // -------------- // VERSION NUMBER // -------------- // ChakraCore version number definitions (used in ChakraCore binary metadata) const CHAKRA_CORE_MAJOR_VERSION = 1; CHAKRA_CORE_MINOR_VERSION = 11; CHAKRA_CORE_PATCH_VERSION = 24; CHAKRA_CORE_VERSION_RELEASE_QFE = 0; // Redundant with PATCH_VERSION. Keep this value set to 0. // ------------- // RELEASE FLAGS // ------------- // NOTE: CHAKRA_CORE_VERSION_PRERELEASE can only be set to 1 when // CHAKRA_CORE_VERSION_RELEASE is set to 1, or there is no effect. // Here are the meanings of the various combinations: // // RELEASE** PRERELEASE // DEVELOPMENT 0 0 // <INVALID> 0 1 # INVALID but identical to DEVELOPMENT // RELEASE** 1 0 # // PRERELEASE 1 1 // ** Release flags are not related to build type (e.g. x64_release) // // Unless otherwise noted, the code affected by these flags lies mostly in bin/CoreCommon.ver // // DEVELOPMENT: // * Uses EngineeringVersioningScheme (see lib/Runtime/ByteCode/ByteCodeSerializer.cpp) // * Sets file flag VS_FF_PRIVATEBUILD // * Adds "Private" to the file description // // RELEASE** and PRERELEASE (i.e. controlled by CHAKRA_CORE_VERSION_RELEASE flag): // * Uses ReleaseVersioningScheme (see lib/Runtime/ByteCode/ByteCodeSerializer.cpp) // // PRERELEASE (preparing for release but not yet ready to release): // * Sets file flag VS_FF_PRERELEASE // * Adds "Pre-release" to the file description // // RELEASE** (code is ready to release) // * Sets neither of the file flags noted above // * Does not add anything to the file description // ChakraCore RELEASE and PRERELEASE flags CHAKRA_CORE_VERSION_RELEASE = 1; CHAKRA_CORE_VERSION_PRERELEASE = 0; // Chakra RELEASE flag // Mostly redundant with CHAKRA_CORE_VERSION_RELEASE, // but semantically refers to Chakra rather than ChakraCore. CHAKRA_VERSION_RELEASE = 0; implementation end. ================================================ FILE: src/ChakraDebug.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) //------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- /// \mainpage Chakra Hosting Debugging API Reference /// /// Chakra is Microsoft's JavaScript engine. It is an integral part of Internet Explorer but can /// also be hosted independently by other applications. This reference describes the APIs available /// to applications to debug JavaScript. /// \file /// \brief The Chakra hosting debugging API. /// /// This file contains a flat C API layer. This is the API exported by ChakraCore.dll. unit ChakraDebug; {$include common.inc} {$minenumsize 4} interface uses ChakraCommon; type /// <summary> /// Debug events reported from ChakraCore engine. /// </summary> JsDiagDebugEvent = ( /// <summary> /// Indicates a new script being compiled, this includes script, eval, new function. /// </summary> JsDiagDebugEventSourceCompile = 0, /// <summary> /// Indicates compile error for a script. /// </summary> JsDiagDebugEventCompileError = 1, /// <summary> /// Indicates a break due to a breakpoint. /// </summary> JsDiagDebugEventBreakpoint = 2, /// <summary> /// Indicates a break after completion of step action. /// </summary> JsDiagDebugEventStepComplete = 3, /// <summary> /// Indicates a break due to debugger statement. /// </summary> JsDiagDebugEventDebuggerStatement = 4, /// <summary> /// Indicates a break due to async break. /// </summary> JsDiagDebugEventAsyncBreak = 5, /// <summary> /// Indicates a break due to a runtime script exception. /// </summary> JsDiagDebugEventRuntimeException = 6 ); /// <summary> /// Break on Exception attributes. /// </summary> JsDiagBreakOnExceptionAttributes = ( /// <summary> /// Don't break on any exception. /// </summary> JsDiagBreakOnExceptionAttributeNone = $0, /// <summary> /// Break on uncaught exception. /// </summary> JsDiagBreakOnExceptionAttributeUncaught = $1, /// <summary> /// Break on first chance exception. /// </summary> JsDiagBreakOnExceptionAttributeFirstChance = $2 ); /// <summary> /// Stepping types. /// </summary> JsDiagStepType = ( /// <summary> /// Perform a step operation to next statement. /// </summary> JsDiagStepTypeStepIn = 0, /// <summary> /// Perform a step out from the current function. /// </summary> JsDiagStepTypeStepOut = 1, /// <summary> /// Perform a single step over after a debug break if the next statement is a function call, else behaves as a stepin. /// </summary> JsDiagStepTypeStepOver = 2, /// <summary> /// Perform a single step back to the previous statement (only applicable in TTD mode). /// </summary> JsDiagStepTypeStepBack = 3, /// <summary> /// Perform a reverse continue operation (only applicable in TTD mode). /// </summary> JsDiagStepTypeReverseContinue = 4, /// <summary> /// Perform a forward continue operation. Clears any existing step value. /// </summary> JsDiagStepTypeContinue = 5 ); /// <summary> /// User implemented callback routine for debug events. /// </summary> /// <remarks> /// Use <c>JsDiagStartDebugging</c> to register the callback. /// </remarks> /// <param name="debugEvent">The type of JsDiagDebugEvent event.</param> /// <param name="eventData">Additional data related to the debug event.</param> /// <param name="callbackState">The state passed to <c>JsDiagStartDebugging</c>.</param> JsDiagDebugEventCallback = function(debugEvent: JsDiagDebugEvent; eventData: JsValueRef; callbackState: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Starts debugging in the given runtime. /// </summary> /// <param name="runtimeHandle">Runtime to put into debug mode.</param> /// <param name="debugEventCallback">Registers a callback to be called on every JsDiagDebugEvent.</param> /// <param name="callbackState">User provided state that will be passed back to the callback.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The runtime should be active on the current thread and should not be in debug state. /// </remarks> function JsDiagStartDebugging(runtimeHandle: JsRuntimeHandle; debugEventCallback: JsDiagDebugEventCallback; callbackState: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Stops debugging in the given runtime. /// </summary> /// <param name="runtimeHandle">Runtime to stop debugging.</param> /// <param name="callbackState">User provided state that was passed in JsDiagStartDebugging.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The runtime should be active on the current thread and in debug state. /// </remarks> function JsDiagStopDebugging(runtimeHandle: JsRuntimeHandle; callbackState: PPointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Request the runtime to break on next JavaScript statement. /// </summary> /// <param name="runtimeHandle">Runtime to request break.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The runtime should be in debug state. This API can be called from another runtime. /// </remarks> function JsDiagRequestAsyncBreak(runtimeHandle: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// List all breakpoints in the current runtime. /// </summary> /// <param name="breakpoints">Array of breakpoints.</param> /// <remarks> /// <para> /// [{ /// "breakpointId" : 1, /// "scriptId" : 1, /// "line" : 0, /// "column" : 62 /// }] /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// </remarks> function JsDiagGetBreakpoints(out breakpoints: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets breakpoint in the specified script at give location. /// </summary> /// <param name="scriptId">Id of script from JsDiagGetScripts or JsDiagGetSource to put breakpoint.</param> /// <param name="lineNumber">0 based line number to put breakpoint.</param> /// <param name="columnNumber">0 based column number to put breakpoint.</param> /// <param name="breakpoint">Breakpoint object with id, line and column if success.</param> /// <remarks> /// <para> /// { /// "breakpointId" : 1, /// "line" : 2, /// "column" : 4 /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// </remarks> function JsDiagSetBreakpoint(scriptId, lineNumber, columnNumber: Cardinal; out breakpoint: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Remove a breakpoint. /// </summary> /// <param name="breakpointId">Breakpoint id returned from JsDiagSetBreakpoint.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// </remarks> function JsDiagRemoveBreakpoint(breakpointId: Cardinal): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets break on exception handling. /// </summary> /// <param name="runtimeHandle">Runtime to set break on exception attributes.</param> /// <param name="exceptionAttributes">Mask of JsDiagBreakOnExceptionAttributes to set.</param> /// <remarks> /// <para> /// If this API is not called the default value is set to JsDiagBreakOnExceptionAttributeUncaught in the runtime. /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The runtime should be in debug state. This API can be called from another runtime. /// </remarks> function JsDiagSetBreakOnException(runtimeHandle: JsRuntimeHandle; exceptionAttributes: JsDiagBreakOnExceptionAttributes): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets break on exception setting. /// </summary> /// <param name="runtimeHandle">Runtime from which to get break on exception attributes, should be in debug mode.</param> /// <param name="exceptionAttributes">Mask of JsDiagBreakOnExceptionAttributes.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The runtime should be in debug state. This API can be called from another runtime. /// </remarks> function JsDiagGetBreakOnException(runtimeHandle: JsRuntimeHandle; out exceptionAttributes: JsDiagBreakOnExceptionAttributes): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Sets the step type in the runtime after a debug break. /// </summary> /// <remarks> /// Requires to be at a debug break. /// </remarks> /// <param name="resumeType">Type of JsDiagStepType.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagSetStepType(stepType: JsDiagStepType): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets list of scripts. /// </summary> /// <param name="scriptsArray">Array of script objects.</param> /// <remarks> /// <para> /// [{ /// "scriptId" : 2, /// "fileName" : "c:\\Test\\Test.js", /// "lineCount" : 4, /// "sourceLength" : 111 /// }, { /// "scriptId" : 3, /// "parentScriptId" : 2, /// "scriptType" : "eval code", /// "lineCount" : 1, /// "sourceLength" : 12 /// }] /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// </remarks> function JsDiagGetScripts(out scriptsArray: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets source for a specific script identified by scriptId from JsDiagGetScripts. /// </summary> /// <param name="scriptId">Id of the script.</param> /// <param name="source">Source object.</param> /// <remarks> /// <para> /// { /// "scriptId" : 1, /// "fileName" : "c:\\Test\\Test.js", /// "lineCount" : 12, /// "sourceLength" : 15154, /// "source" : "var x = 1;" /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can be called when runtime is at a break or running. /// </remarks> function JsDiagGetSource(scriptId: Cardinal; out source: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the source information for a function object. /// </summary> /// <param name="function">JavaScript function.</param> /// <param name="functionPosition">Function position - scriptId, start line, start column, line number of first statement, column number of first statement.</param> /// <remarks> /// <para> /// { /// "scriptId" : 1, /// "fileName" : "c:\\Test\\Test.js", /// "line" : 1, /// "column" : 2, /// "firstStatementLine" : 6, /// "firstStatementColumn" : 0 /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// This API can be called when runtime is at a break or running. /// </remarks> function JsDiagGetFunctionPosition(_function: JsValueRef; out functionPosition: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the stack trace information. /// </summary> /// <param name="stackTrace">Stack trace information.</param> /// <remarks> /// <para> /// [{ /// "index" : 0, /// "scriptId" : 2, /// "line" : 3, /// "column" : 0, /// "sourceLength" : 9, /// "sourceText" : "var x = 1", /// "functionHandle" : 1 /// }] /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagGetStackTrace(out stackTrace: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the list of properties corresponding to the frame. /// </summary> /// <param name="stackFrameIndex">Index of stack frame from JsDiagGetStackTrace.</param> /// <param name="properties">Object of properties array (properties, scopes and globals).</param> /// <remarks> /// <para> /// propertyAttributes is a bit mask of /// NONE = 0x1, /// HAVE_CHILDRENS = 0x2, /// READ_ONLY_VALUE = 0x4, /// IN_TDZ = 0x8, /// </para> /// <para> /// { /// "thisObject": { /// "name": "this", /// "type" : "object", /// "className" : "Object", /// "display" : "{...}", /// "propertyAttributes" : 1, /// "handle" : 306 /// }, /// "exception" : { /// "name" : "{exception}", /// "type" : "object", /// "display" : "'a' is undefined", /// "className" : "Error", /// "propertyAttributes" : 1, /// "handle" : 307 /// } /// "arguments" : { /// "name" : "arguments", /// "type" : "object", /// "display" : "{...}", /// "className" : "Object", /// "propertyAttributes" : 1, /// "handle" : 190 /// }, /// "returnValue" : { /// "name" : "[Return value]", /// "type" : "undefined", /// "propertyAttributes" : 0, /// "handle" : 192 /// }, /// "functionCallsReturn" : [{ /// "name" : "[foo1 returned]", /// "type" : "number", /// "value" : 1, /// "propertyAttributes" : 2, /// "handle" : 191 /// } /// ], /// "locals" : [], /// "scopes" : [{ /// "index" : 0, /// "handle" : 193 /// } /// ], /// "globals" : { /// "handle" : 194 /// } /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagGetStackProperties(stackFrameIndex: Cardinal; out properties: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the list of children of a handle. /// </summary> /// <param name="objectHandle">Handle of object.</param> /// <param name="fromCount">0-based from count of properties, usually 0.</param> /// <param name="totalCount">Number of properties to return.</param> /// <param name="propertiesObject">Array of properties.</param> /// <remarks>Handle should be from objects returned from call to JsDiagGetStackProperties.</remarks> /// <remarks>For scenarios where object have large number of properties totalCount can be used to control how many properties are given.</remarks> /// <remarks> /// <para> /// { /// "totalPropertiesOfObject": 10, /// "properties" : [{ /// "name" : "__proto__", /// "type" : "object", /// "display" : "{...}", /// "className" : "Object", /// "propertyAttributes" : 1, /// "handle" : 156 /// } /// ], /// "debuggerOnlyProperties" : [{ /// "name" : "[Map]", /// "type" : "string", /// "value" : "size = 0", /// "propertyAttributes" : 2, /// "handle" : 157 /// } /// ] /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagGetProperties(objectHandle, fromCount, totalCount: Cardinal; out propertiesObject: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Gets the object corresponding to handle. /// </summary> /// <param name="objectHandle">Handle of object.</param> /// <param name="handleObject">Object corresponding to the handle.</param> /// <remarks> /// <para> /// { /// "scriptId" : 24, /// "line" : 1, /// "column" : 63, /// "name" : "foo", /// "type" : "function", /// "handle" : 2 /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagGetObjectFromHandle(objectHandle: Cardinal; out handleObject: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// Evaluates an expression on given frame. /// </summary> /// <param name="expression"> /// Javascript String or ArrayBuffer (incl. ExternalArrayBuffer). /// </param> /// <param name="stackFrameIndex">Index of stack frame on which to evaluate the expression.</param> /// <param name="parseAttributes"> /// Defines how `expression` (JsValueRef) should be parsed. /// - `JsParseScriptAttributeNone` when `expression` is a Utf8 encoded ArrayBuffer and/or a Javascript String (encoding independent) /// - `JsParseScriptAttributeArrayBufferIsUtf16Encoded` when `expression` is Utf16 Encoded ArrayBuffer /// - `JsParseScriptAttributeLibraryCode` has no use for this function and has similar effect with `JsParseScriptAttributeNone` /// </param> /// <param name="forceSetValueProp">Forces the result to contain the raw value of the expression result.</param> /// <param name="evalResult">Result of evaluation.</param> /// <remarks> /// <para> /// evalResult when evaluating 'this' and return is JsNoError /// { /// "name" : "this", /// "type" : "object", /// "className" : "Object", /// "display" : "{...}", /// "propertyAttributes" : 1, /// "handle" : 18 /// } /// /// evalResult when evaluating a script which throws JavaScript error and return is JsErrorScriptException /// { /// "name" : "a.b.c", /// "type" : "object", /// "className" : "Error", /// "display" : "'a' is undefined", /// "propertyAttributes" : 1, /// "handle" : 18 /// } /// </para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, evalResult will contain the result /// The code <c>JsErrorScriptException</c> if evaluate generated a JavaScript exception, evalResult will contain the error details /// Other error code for invalid parameters or API was not called at break /// </returns> /// <remarks> /// The current runtime should be in debug state. This API can only be called when runtime is at a break. /// </remarks> function JsDiagEvaluate(expression: JsValueRef; stackFrameIndex: Cardinal; parseAttributes: JsParseScriptAttributes; forceSetValueProp: bool; out evalResult: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} type ///////////////////// /// <summary> /// TimeTravel move options as bit flag enum. /// </summary> JsTTDMoveModes = ( /// <summary> /// Indicates no special actions needed for move. /// </summary> JsTTDMoveNone = $0, /// <summary> /// Indicates that we want to move to the first event. /// </summary> JsTTDMoveFirstEvent = $1, /// <summary> /// Indicates that we want to move to the last event. /// </summary> JsTTDMoveLastEvent = $2, /// <summary> /// Indicates that we want to move to the kth event -- top 32 bits are event count. /// </summary> JsTTDMoveKthEvent = $4, /// <summary> /// Indicates if we are doing the scan for a continue operation /// </summary> JsTTDMoveScanIntervalForContinue = $10, /// <summary> /// Indicates if we are doing the scan for a continue operation and are in the time-segment where the active breakpoint was /// </summary> JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment = $20, /// <summary> /// Indicates if we want to set break on entry or just run and let something else trigger breakpoints. /// </summary> JsTTDMoveBreakOnEntry = $100 ); JsTTDMoveMode = Cardinal; /// <summary> /// A handle for URI's that TTD information is written to/read from. /// </summary> JsTTDStreamHandle = Pointer; /// <summary> /// TTD API -- may change in future versions: /// Construct a JsTTDStreamHandle that will be used to read/write the event log portion of the TTD data based on the uri /// provided by JsTTDInitializeUriCallback. /// </summary> /// <remarks> /// <para>Exactly one of read or write will be set to true.</para> /// </remarks> /// <param name="uriLength">The length of the uri array that the host passed in for storing log info.</param> /// <param name="uri">The URI that the host passed in for storing log info.</param> /// <param name="asciiNameLength">The length of the ascii name array that the host passed in for storing log info.</param> /// <param name="asciiResourceName">An optional ascii string giving a unique name to the resource that the JsTTDStreamHandle will be created for.</param> /// <param name="read">If the handle should be opened for reading.</param> /// <param name="write">If the handle should be opened for writing.</param> /// <returns>A JsTTDStreamHandle opened in read/write mode as specified.</returns> TTDOpenResourceStreamCallback = function(uriLength: size_t; uri: PAnsiChar; asciiNameLength: size_t; asciiResourceName: PAnsiChar; read, write: bool): JsTTDStreamHandle; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// A callback for reading data from a handle. /// </summary> /// <param name="handle">The JsTTDStreamHandle to read the data from.</param> /// <param name="buff">The buffer to place the data into.</param> /// <param name="size">The max number of bytes that should be read.</param> /// <param name="readCount">The actual number of bytes read and placed in the buffer.</param> /// <returns>true if the read was successful false otherwise.</returns> JsTTDReadBytesFromStreamCallback = function(handle: JsTTDStreamHandle; buff: PByte; size: size_t; out readCount: size_t): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// A callback for writing data to a handle. /// </summary> /// <param name="handle">The JsTTDStreamHandle to write the data to.</param> /// <param name="buff">The buffer to copy the data from.</param> /// <param name="size">The max number of bytes that should be written.</param> /// <param name="readCount">The actual number of bytes written to the HANDLE.</param> /// <returns>true if the write was successful false otherwise.</returns> JsTTDWriteBytesToStreamCallback = function (handle: JsTTDStreamHandle; buff: PByte; size: size_t; out writtenCount: size_t): bool; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Flush and close the stream represented by the HANDLE as needed. /// </summary> /// <remarks> /// <para>Exactly one of read or write will be set to true.</para> /// </remarks> /// <param name="handle">The JsTTDStreamHandle to close.</param> /// <param name="read">If the handle was opened for reading.</param> /// <param name="write">If the handle was opened for writing.</param> JsTTDFlushAndCloseStreamCallback = procedure(handle: JsTTDStreamHandle; read, write: bool); {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Creates a new runtime in Record Mode. /// </summary> /// <param name="attributes">The attributes of the runtime to be created.</param> /// <param name="enableDebugging">A flag to enable debugging during record.</param> /// <param name="snapInterval">The interval to wait between snapshots (measured in millis).</param> /// <param name="snapHistoryLength">The amount of history to maintain before discarding -- measured in number of snapshots and controls how far back in time a trace can be reversed.</param> /// <param name="openResourceStream">The <c>TTDOpenResourceStreamCallback</c> function for generating a JsTTDStreamHandle to read/write serialized data.</param> /// <param name="writeBytesToStream">The <c>JsTTDWriteBytesToStreamCallback</c> function for writing bytes to a JsTTDStreamHandle.</param> /// <param name="flushAndCloseStream">The <c>JsTTDFlushAndCloseStreamCallback</c> function for flushing and closing a JsTTDStreamHandle as needed.</param> /// <param name="threadService">The thread service for the runtime. Can be null.</param> /// <param name="runtime">The runtime created.</param> /// <remarks> /// <para>See <c>JsCreateRuntime</c> for additional information.</para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsTTDCreateRecordRuntime(attributes: JsRuntimeAttributes; enableDebugging: bool; snapInterval, snapHistoryLength: size_t; openResourceStream: TTDOpenResourceStreamCallback; writeBytesToStream: JsTTDWriteBytesToStreamCallback; flushAndCloseStream: JsTTDFlushAndCloseStreamCallback; threadService: JsThreadServiceCallback; out runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Creates a new runtime in Debug Mode. /// </summary> /// <param name="attributes">The attributes of the runtime to be created.</param> /// <param name="infoUri">The uri where the recorded Time-Travel data should be loaded from.</param> /// <param name="enableDebugging">A flag to enable additional debugging operation support during replay.</param> /// <param name="openResourceStream">The <c>TTDOpenResourceStreamCallback</c> function for generating a JsTTDStreamHandle to read/write serialized data.</param> /// <param name="readBytesFromStream">The <c>JsTTDReadBytesFromStreamCallback</c> function for reading bytes from a JsTTDStreamHandle.</param> /// <param name="flushAndCloseStream">The <c>JsTTDFlushAndCloseStreamCallback</c> function for flushing and closing a JsTTDStreamHandle as needed.</param> /// <param name="threadService">The thread service for the runtime. Can be null.</param> /// <param name="runtime">The runtime created.</param> /// <remarks> /// <para>See <c>JsCreateRuntime</c> for additional information.</para> /// </remarks> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsTTDCreateReplayRuntime(attributes: JsRuntimeAttributes; infoUri: PAnsiChar; infoUriCount: size_t; enableDebugging: bool; openResourceStream: TTDOpenResourceStreamCallback; readBytesFromStream: JsTTDReadBytesFromStreamCallback; flushAndCloseStream: JsTTDFlushAndCloseStreamCallback; threadService: JsThreadServiceCallback; out runtime: JsRuntimeHandle): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Creates a script context that takes the TTD mode from the log or explicitly is not in TTD mode (regular takes mode from currently active script). /// </summary> /// <param name="runtime">The runtime the script context is being created in.</param> /// <param name="useRuntimeTTDMode">Set to true to use runtime TTD mode false to explicitly be non-TTD context.</param> /// <param name="newContext">The created script context.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsTTDCreateContext(runtimeHandle: JsRuntimeHandle; useRuntimeTTDMode: bool; out newContext: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the time-travel system that a context has been identified as dead by the gc (and is being de-allocated). /// </summary> /// <param name="context">The script context that is now dead.</param> /// <returns> /// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. /// </returns> function JsTTDNotifyContextDestroy(context: JsContextRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Start Time-Travel record or replay at next turn of event loop. /// </summary> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDStart: JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Stop Time-Travel record or replay. /// </summary> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDStop: JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Pause Time-Travel recording before executing code on behalf of debugger or other diagnostic/telemetry. /// </summary> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDPauseTimeTravelBeforeRuntimeOperation: JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// ReStart Time-Travel recording after executing code on behalf of debugger or other diagnostic/telemetry. /// </summary> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDReStartTimeTravelAfterRuntimeOperation: JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the Js runtime we are at a safe yield point in the event loop (i.e. no locals on the stack and we can process as desired). /// </summary> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDNotifyYield: JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the TTD runtime that we are doing a weak add on a reference (we may use this in external API calls and the release will happen in a GC callback). /// </summary> /// <param name="value">The value we are adding the ref to.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDNotifyLongLivedReferenceAdd(value: JsValueRef): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the Js runtime the host is aborting the process and what the status code is. /// </summary> /// <param name="statusCode">The exit status code.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDHostExit(statusCode: Integer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the event log that the contents of one buffer have been copied to a second buffer. /// </summary> /// <param name="dst">The buffer that was written into.</param> /// <param name="dstIndex">The first index modified.</param> /// <param name="src">The buffer that was copied from.</param> /// <param name="srcIndex">The first index copied.</param> /// <param name="count">The number of bytes copied.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDRawBufferCopySyncIndirect(dst: JsValueRef; dstIndex: size_t; src: JsValueRef; srcIndex, count: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the event log that the contents of a naked byte* buffer passed to the host have been modified synchronously. /// </summary> /// <param name="buffer">The buffer that was modified.</param> /// <param name="index">The first index modified.</param> /// <param name="count">The number of bytes written.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDRawBufferModifySyncIndirect(buffer: JsValueRef; index, count: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Get info for notifying the TTD system that a raw buffer it shares with the host has been modified. /// </summary> /// <param name="instance">The array buffer we want to monitor for contents modification.</param> /// <param name="initialModPos">The first position in the buffer that may be modified.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDRawBufferAsyncModificationRegister(instance: JsValueRef; initialModPos: PByte): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Notify the event log that the contents of a naked byte* buffer passed to the host have been modified asynchronously. /// </summary> /// <param name="finalModPos">One past the last modified position in the buffer.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDRawBufferAsyncModifyComplete(finalModPos: PByte): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// A check for unimplemented TTD actions in the host. /// This API is a TEMPORARY API while we complete the implementation of TTD support in the Node host and will be deleted once that is complete. /// </summary> /// <param name="msg">The message to print if we should be catching this as a TTD operation.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDCheckAndAssertIfTTDRunning(msg: PAnsiChar): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Before calling JsTTDMoveToTopLevelEvent (which inflates a snapshot and replays) check to see if we want to reset the script context. /// We reset the script context if the move will require inflating from a different snapshot that the last one. /// </summary> /// <param name="runtimeHandle">The runtime handle that the script is executing in.</param> /// <param name="moveMode">Flags controlling the way the move it performed and how other parameters are interpreted.</param> /// <param name="kthEvent">When <c>moveMode == JsTTDMoveKthEvent</c> indicates which event, otherwise this parameter is ignored.</param> /// <param name="targetEventTime">The event time we want to move to or -1 if not relevant.</param> /// <param name="targetStartSnapTime">Out parameter with the event time of the snapshot that we should inflate from.</param> /// <param name="targetEndSnapTime">Optional Out parameter with the snapshot time following the event.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDGetSnapTimeTopLevelEventMove(runtimeHandle: JsRuntimeHandle; moveMode: JsTTDMoveMode; kthEvent: Cardinal; targetEventTime: Int64; out targetStartSnapTime: Int64; targetEndSnapTime: PInt64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Get the snapshot interval that bounds the target event time. /// </summary> /// <param name="runtimeHandle">The runtime handle that the script is executing in.</param> /// <param name="targetEventTime">The event time we want to get the interval for.</param> /// <param name="startSnapTime">The snapshot time that comes before the desired event.</param> /// <param name="endSnapTime">The snapshot time that comes after the desired event (-1 if the leg ends before a snapshot appears).</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDGetSnapShotBoundInterval(runtimeHandle: JsRuntimeHandle; targetEventTime: Int64; out startSnapTime, endSnapTime: Int64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Get the snapshot interval that precedes the one given by currentSnapStartTime (or -1 if there is no such interval). /// </summary> /// <param name="runtimeHandle">The runtime handle that the script is executing in.</param> /// <param name="currentSnapStartTime">The current snapshot interval start time.</param> /// <param name="previousSnapTime">The resulting previous snapshot interval start time or -1 if no such time.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDGetPreviousSnapshotInterval(runtimeHandle: JsRuntimeHandle; currentSnapStartTime: Int64; out previousSnapTime: Int64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// During debug operations some additional information is populated during replay. This runs the code between the given /// snapshots to populate this information which may be needed by the debugger to determine time-travel jump targets. /// </summary> /// <param name="runtimeHandle">The runtime handle that the script is executing in.</param> ///<param name = "startSnapTime">The snapshot time that we will start executing from.< / param> ///<param name = "endSnapTime">The snapshot time that we will stop at (or -1 if we want to run to the end).< / param> /// <param name="moveMode">Additional flags for controling how the move is done.</param> /// <param name="newTargetEventTime">The updated target event time set according to the moveMode (-1 if not found).</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDPreExecuteSnapShotInterval(runtimeHandle: JsRuntimeHandle; startSnapTime, endSnapTime: Int64; moveMode: JsTTDMoveMode; out newTargetEventTime: Int64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Move to the given top-level call event time (assuming JsTTDPrepContextsForTopLevelEventMove) was called previously to reset any script contexts. /// This also computes the ready-to-run snapshot if needed. /// </summary> /// <param name="runtimeHandle">The runtime handle that the script is executing in.</param> /// <param name="moveMode">Additional flags for controling how the move is done.</param> /// <param name="snapshotTime">The event time that we will start executing from to move to the given target time.</param> /// <param name="eventTime">The event that we want to move to.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDMoveToTopLevelEvent(runtimeHandle: JsRuntimeHandle; moveMode: JsTTDMoveMode; snapshotTime, eventTime: Int64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Execute from the current point in the log to the end returning the error code. /// </summary> /// <param name="moveMode">Additional flags for controling how the move is done.</param> /// <param name="rootEventTime">The event time that we should move to next or notification (-1) that replay has ended.</param> /// <returns> /// If the debugger requested an abort the code is JsNoError -- rootEventTime is the target event time we need to move to and re - execute from. /// If we aborted at the end of the replay log the code is JsNoError -- rootEventTime is -1. /// If there was an unhandled script exception the code is JsErrorCategoryScript. /// </returns> function JsTTDReplayExecution(moveMode: JsTTDMoveMode; out rootEventTime: Int64): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// Enable or disable autotrace ability from JsRT. /// </summary> /// <param name="status">True to enable autotracing false to disable it.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDDiagSetAutoTraceStatus(status: bool): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} /// <summary> /// TTD API -- may change in future versions: /// A way for the debugger to programatically write a trace when it is at a breakpoint. /// </summary> /// <param name="uri">The URI that the log should be written into.</param> /// <param name="uriLength">The length of the uri array that the host passed in for storing log info.</param> /// <returns>The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.</returns> function JsTTDDiagWriteLog(uri: PAnsiChar; uriLength: size_t): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} implementation {$ifdef MSWINDOWS} const _chakracore = 'chakracore.dll'; {$endif} {$ifdef DARWIN} const _chakracore = 'libChakraCore.dylib'; {$endif} {$ifdef LINUX} const _chakracore = 'libChakraCore.so'; {$endif} function JsDiagStartDebugging; external _chakracore; function JsDiagStopDebugging; external _chakracore; function JsDiagRequestAsyncBreak; external _chakracore; function JsDiagGetBreakpoints; external _chakracore; function JsDiagSetBreakpoint; external _chakracore; function JsDiagRemoveBreakpoint; external _chakracore; function JsDiagSetBreakOnException; external _chakracore; function JsDiagGetBreakOnException; external _chakracore; function JsDiagSetStepType; external _chakracore; function JsDiagGetScripts; external _chakracore; function JsDiagGetSource; external _chakracore; function JsDiagGetFunctionPosition; external _chakracore; function JsDiagGetStackTrace; external _chakracore; function JsDiagGetStackProperties; external _chakracore; function JsDiagGetProperties; external _chakracore; function JsDiagGetObjectFromHandle; external _chakracore; function JsDiagEvaluate; external _chakracore; function JsTTDCreateRecordRuntime; external _chakracore; function JsTTDCreateReplayRuntime; external _chakracore; function JsTTDCreateContext; external _chakracore; function JsTTDNotifyContextDestroy; external _chakracore; function JsTTDStart; external _chakracore; function JsTTDStop; external _chakracore; function JsTTDPauseTimeTravelBeforeRuntimeOperation; external _chakracore; function JsTTDReStartTimeTravelAfterRuntimeOperation; external _chakracore; function JsTTDNotifyYield; external _chakracore; function JsTTDNotifyLongLivedReferenceAdd; external _chakracore; function JsTTDHostExit; external _chakracore; function JsTTDRawBufferCopySyncIndirect; external _chakracore; function JsTTDRawBufferModifySyncIndirect; external _chakracore; function JsTTDRawBufferAsyncModificationRegister; external _chakracore; function JsTTDRawBufferAsyncModifyComplete; external _chakracore; function JsTTDCheckAndAssertIfTTDRunning; external _chakracore; function JsTTDGetSnapTimeTopLevelEventMove; external _chakracore; function JsTTDGetSnapShotBoundInterval; external _chakracore; function JsTTDGetPreviousSnapshotInterval; external _chakracore; function JsTTDPreExecuteSnapShotInterval; external _chakracore; function JsTTDMoveToTopLevelEvent; external _chakracore; function JsTTDReplayExecution; external _chakracore; function JsTTDDiagSetAutoTraceStatus; external _chakracore; function JsTTDDiagWriteLog; external _chakracore; end. ================================================ FILE: src/Compat.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit Compat; interface {$include common.inc} {$ifdef FPC} {$macro ON} {$warn SYMBOL_PLATFORM OFF} {$endif} uses {$ifdef DELPHI} Windows, {$endif} SysUtils; {$ifndef HAS_NATIVEUINT} type PNativeUInt = ^NativeUInt; NativeUInt = Cardinal; {$endif} {$ifndef HAS_RAWBYTESTRING} type RawByteString = AnsiString; {$endif} {$ifndef HAS_UINTPTR} type PUIntPtr = ^UIntPtr; UIntPtr = NativeUInt; {$endif} {$ifndef HAS_WSTRPOS} function WStrPos(const Str1, Str2: PWideChar): PWideChar; {$endif} type PUnicodeChar = ^UnicodeChar; UnicodeChar = WideChar; {$ifndef SUPPORTS_UNICODE_STRING} type PUnicodeString = ^UnicodeString; UnicodeString = WideString; {$endif} {$ifdef DELPHI} function UnicodeFormat(const Format: UnicodeString; const Args: array of const): UnicodeString; function UnicodeSameText(const S1, S2: UnicodeString): Boolean; function UnicodeStringReplace(const S, OldPattern, NewPattern: UnicodeString; Flags: TReplaceFlags): UnicodeString; {$endif DELPHI} function GetBuildInfoString: string; function GetExeFileVersionString: string; {$ifdef FPC} var UTF8ToString: function(const S: RawByteString): UnicodeString = @UTF8Decode; {$endif} {$ifdef DELPHI} // initialize to US format settings (use point as decimal separator for float values) var DefaultFormatSettings: TFormatSettings; procedure InitCriticalSection(var Lock: TRTLCriticalSection); procedure DoneCriticalSection(var Lock: TRTLCriticalSection); {$ifndef HAS_WIDESTRUTILS} function WideStringReplace(const S, OldPattern, NewPattern: Widestring; Flags: TReplaceFlags): Widestring; {$endif} {$ifndef UNICODE} var UTF8ToString: function(const S: UTF8String): WideString; {$endif} {$endif DELPHI} implementation {$ifdef FPC} uses {$ifdef WINDOWS} winpeimagereader, {$endif} {$ifdef LINUX} elfreader, {$endif} {$ifdef DARWIN} machoreader, {$endif} fileinfo; {$endif} {$ifdef FPC} function GetBuildInfoString: string; begin Result := Format('FPC %d.%d.%d for %s-%s', [FPC_VERSION, FPC_RELEASE, FPC_PATCH, lowercase({$i %FPCTARGETOS%}), lowercase({$i %FPCTARGETCPU%})]) end; function GetExeFileVersionString: string; var FileVersionInfo: TFileVersionInfo; begin FileVersionInfo := TFileVersionInfo.Create(nil); try FileVersionInfo.ReadFileInfo; Result := FileVersionInfo.VersionStrings.Values['FileVersion']; finally FileVersionInfo.Free; end; end; {$ifndef HAS_WSTRPOS} function WStrPos(const Str1, Str2: PWideChar): PWideChar; begin Result := strpos(Str1, Str2); end; {$endif} {$endif} {$ifdef DELPHI} procedure InitCriticalSection(var Lock: TRTLCriticalSection); begin InitializeCriticalSection(Lock); end; procedure DoneCriticalSection(var Lock: TRTLCriticalSection); begin Windows.DeleteCriticalSection(Lock); end; {$ifndef HAS_WIDESTRUTILS} function WideStringReplace(const S, OldPattern, NewPattern: Widestring; Flags: TReplaceFlags): Widestring; var SearchStr, Patt, NewStr: Widestring; Offset: Integer; begin if rfIgnoreCase in Flags then begin SearchStr := WideUpperCase(S); Patt := WideUpperCase(OldPattern); end else begin SearchStr := S; Patt := OldPattern; end; NewStr := S; Result := ''; while SearchStr <> '' do begin Offset := Pos(Patt, SearchStr); if Offset = 0 then begin Result := Result + NewStr; Break; end; Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); if not (rfReplaceAll in Flags) then begin Result := Result + NewStr; Break; end; SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); end; end; {$endif} {$ifdef DELPHI} function UnicodeFormat(const Format: UnicodeString; const Args: array of const): UnicodeString; begin {$ifdef UNICODE} Result := SysUtils.Format(Format, Args); {$else} Result := WideFormat(Format, Args); {$endif} end; function UnicodeSameText(const S1, S2: UnicodeString): Boolean; begin {$ifdef UNICODE} Result := SameText(S1, S2); {$else} Result := WideSameText(S1, S2); {$endif} end; function UnicodeStringReplace(const S, OldPattern, NewPattern: UnicodeString; Flags: TReplaceFlags): UnicodeString; begin {$ifdef UNICODE} Result := StringReplace(S, OldPattern, NewPattern, Flags); {$ELSE} Result := WideStringReplace(S, OldPattern, NewPattern, Flags); {$ENDIF} end; {$endif DELPHI} {$ifdef DELPHIXE2_UP} const ArchitectureStrings: array[TOSVersion.TArchitecture] of string = ('x86', 'x64', 'arm32'{$ifdef DELPHIX_BERLIN_UP}, 'arm64'{$endif}); PlatformStrings: array[TOSVersion.TPlatform] of string = ('Windows', 'MacOS', 'iOS', 'Android', 'WinRT', 'Linux'); {$endif} function GetBuildInfoString: string; begin {$ifdef DELPHIXE2_UP} Result := Format('Delphi %.1f for %s-%s', [System.CompilerVersion, PlatformStrings[TOSVersion.Platform], ArchitectureStrings[TOSVersion.Architecture]], DefaultFormatSettings); {$else} Result := Format('Delphi %.1f for Windows-x86', [CompilerVersion], DefaultFormatSettings); {$endif} end; function GetExeFileVersionString: string; var Ver: LongRec; begin Ver := LongRec(GetFileVersion(Paramstr(0))); Result := Format('%u.%u', [Ver.Hi, Ver.Lo]); end; {$ifndef HAS_WSTRPOS} function WStrPos(const Str1, Str2: PWideChar): PWideChar; var Str, SubStr: PWideChar; Ch: WideChar; begin Result := nil; if (Str1 = nil) or (Str1^ = #0) or (Str2 = nil) or (Str2^ = #0) then Exit; Result := Str1; Ch := Str2^; repeat if Result^ = Ch then begin Str := Result; SubStr := Str2; repeat Inc(Str); Inc(SubStr); if SubStr^ = #0 then exit; if Str^ = #0 then begin Result := nil; exit; end; if Str^ <> SubStr^ then break; until (FALSE); end; Inc(Result); until (Result^ = #0); Result := nil; end; {$endif} {$endif} initialization {$ifdef DELPHI} {$ifndef UNICODE} UTF8ToString := @UTF8Decode; {$endif} {$ifdef DELPHIXE_UP} DefaultFormatSettings := TFormatSettings.Create('en-US'); {$else} GetLocaleFormatSettings(1033, DefaultFormatSettings); {$endif} {$endif} {$ifdef FPC} {$ifdef WINDOWS} GetLocaleFormatSettings(1033, DefaultFormatSettings); {$endif} {$endif} finalization end. ================================================ FILE: src/common.inc ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) {$include ..\ext\jedi\jedi.inc} {$ifdef MSWINDOWS} {$define WINDOWS} {$endif} {$ifdef FPC} {$ifdef UNIX} {$define UseCThreads} {$endif} {$define HAS_NATIVEUINT} {$define HAS_RAWBYTESTRING} {$define HAS_UINTPTR} {$define SUPPORTS_CLASS_FIELDS} {$define SUPPORTS_UNICODE_STRING} {$endif} {$ifdef DELPHI} {$ifdef DELPHIXE_UP} {$define HAS_NATIVEUINT} {$endif} {$ifdef DELPHI2009_UP} {$define HAS_RAWBYTESTRING} {$endif} {$ifdef DELPHIXE2_UP} {$define HAS_UINTPTR} {$endif} {$ifdef DELPHI2007_UP} {$define HAS_WIDESTRUTILS} {$endif} {$endif} ================================================ FILE: tests/ChakraCoreTests.XE.dproj ================================================  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProjectGuid>{31F06C91-6ED6-4632-93E5-4C71AFB559F7}</ProjectGuid> <MainSource>ChakraCoreTests.dpr</MainSource> <Config Condition="'$(Config)'==''">Debug</Config> <DCC_DCCCompiler>DCC32</DCC_DCCCompiler> <ProjectVersion>12.3</ProjectVersion> <Base>True</Base> <Platform>Win32</Platform> <AppType>Console</AppType> <FrameworkType>None</FrameworkType> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> <Cfg_1>true</Cfg_1> <CfgParent>Base</CfgParent> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> <Cfg_2>true</Cfg_2> <CfgParent>Base</CfgParent> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Base)'!=''"> <DCC_DependencyCheckOutputName>..\bin\$(Platform)\$(Config)\ChakraCoreTests.exe</DCC_DependencyCheckOutputName> <DCC_ExeOutput>..\bin\$(Platform)\$(Config)</DCC_ExeOutput> <DCC_DcuOutput>..\lib\$(Platform)\$(Config)</DCC_DcuOutput> <DCC_ImageBase>00400000</DCC_ImageBase> <DCC_UsePackage>vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers</DCC_UsePackage> <DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias)</DCC_UnitAlias> <DCC_Platform>x86</DCC_Platform> <DCC_UnitSearchPath>..\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> <DCC_K>false</DCC_K> <DCC_N>true</DCC_N> <DCC_S>false</DCC_S> <DCC_SymbolReferenceInfo>1</DCC_SymbolReferenceInfo> <DCC_E>false</DCC_E> <DCC_F>false</DCC_F> <DCC_ConsoleTarget>true</DCC_ConsoleTarget> </PropertyGroup> <PropertyGroup Condition="'$(Cfg_1)'!=''"> <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> <DCC_DebugInformation>false</DCC_DebugInformation> </PropertyGroup> <PropertyGroup Condition="'$(Cfg_2)'!=''"> <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> </PropertyGroup> <ItemGroup> <DelphiCompile Include="ChakraCoreTests.dpr"> <MainSource>MainSource</MainSource> </DelphiCompile> <BuildConfiguration Include="Debug"> <Key>Cfg_2</Key> <CfgParent>Base</CfgParent> </BuildConfiguration> <BuildConfiguration Include="Base"> <Key>Base</Key> </BuildConfiguration> <BuildConfiguration Include="Release"> <Key>Cfg_1</Key> <CfgParent>Base</CfgParent> </BuildConfiguration> </ItemGroup> <Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/> <Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/> <ProjectExtensions> <Borland.Personality>Delphi.Personality.12</Borland.Personality> <Borland.ProjectType>VCLApplication</Borland.ProjectType> <BorlandProject> <Delphi.Personality> <Source> <Source Name="MainSource">ChakraCoreTests.dpr</Source> </Source> <Parameters/> <VersionInfo> <VersionInfo Name="IncludeVerInfo">True</VersionInfo> <VersionInfo Name="AutoIncBuild">False</VersionInfo> <VersionInfo Name="MajorVer">1</VersionInfo> <VersionInfo Name="MinorVer">0</VersionInfo> <VersionInfo Name="Release">0</VersionInfo> <VersionInfo Name="Build">0</VersionInfo> <VersionInfo Name="Debug">False</VersionInfo> <VersionInfo Name="PreRelease">False</VersionInfo> <VersionInfo Name="Special">False</VersionInfo> <VersionInfo Name="Private">False</VersionInfo> <VersionInfo Name="DLL">False</VersionInfo> <VersionInfo Name="Locale">1033</VersionInfo> <VersionInfo Name="CodePage">1252</VersionInfo> </VersionInfo> <VersionInfoKeys> <VersionInfoKeys Name="CompanyName"/> <VersionInfoKeys Name="FileDescription"/> <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="InternalName">ChakraCoreTests</VersionInfoKeys> <VersionInfoKeys Name="LegalCopyright">© 2021 Ondrej Kelle</VersionInfoKeys> <VersionInfoKeys Name="LegalTrademarks"/> <VersionInfoKeys Name="OriginalFilename">ChakraCoreTests</VersionInfoKeys> <VersionInfoKeys Name="ProductName">chakracore-delphi</VersionInfoKeys> <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="Comments"/> </VersionInfoKeys> </Delphi.Personality> <Platforms> <Platform value="Win32">True</Platform> </Platforms> </BorlandProject> <ProjectFileVersion>12</ProjectFileVersion> </ProjectExtensions> </Project> ================================================ FILE: tests/ChakraCoreTests.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=0 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\bin\Win32\Debug UnitOutputDir=..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\src Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=ChakraCoreTests LegalCopyright=� 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=ChakraCoreTests ProductName=chakracore-delphi ProductVersion=1.0.0.0 Comments= [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: tests/ChakraCoreTests.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program ChakraCoreTests; {$include ..\src\common.inc} {$ifdef FPC} {$macro ON} {$endif} {$ifdef CONSOLE_TESTRUNNER} {$apptype CONSOLE} {$endif} uses SysUtils, Classes, {$ifdef FPC} consoletestrunner, fpcunitreport, plaintestreport, {$endif} {$ifdef DELPHI} TextTestRunner, {$endif} Compat, ChakraCoreVersion, Test_ChakraCore, Test_Classes; {$R *.res} {$ifdef FPC} var Application: TTestRunner; {$endif} begin Writeln(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); Writeln(Format('Built with %s', [GetBuildInfoString])); Writeln(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); Writeln; {$ifdef FPC} Application := TTestRunner.Create(nil); try Application.Initialize; Application.Run; finally Application.Free; end; {$endif} {$ifdef DELPHI} RunRegisteredTests; {$endif} end. ================================================ FILE: tests/ChakraCoreTests.lpi ================================================ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="10"/> <General> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="ChakraCoreTests"/> <UseAppBundle Value="False"/> <ResourceType Value="res"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="1"/> <StringTable InternalName="ChakraCoreTests" LegalCopyright="© 2021 Ondrej Kelle" OriginalFilename="ChakraCoreTests" ProductName="chakracore-delphi"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Debug" Default="True"/> <Item2 Name="Release"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="bin/$(TargetCPU)-$(TargetOS)/ChakraCoreTests"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../src"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="DelphiUnicode"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <local> <FormatVersion Value="1"/> <CommandLineParams Value="-a -p --format=plain"/> </local> <environment> <UserOverrides Count="1"> <Variable0 Name="LD_LIBRARY_PATH" Value="$Path($TargetFile)"/> </UserOverrides> </environment> </RunParams> <RequiredPackages Count="1"> <Item1> <PackageName Value="FCL"/> </Item1> </RequiredPackages> <Units Count="3"> <Unit0> <Filename Value="ChakraCoreTests.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="Test_ChakraCore.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="Test_Classes.pas"/> <IsPartOfProject Value="True"/> </Unit2> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)/ChakraCoreTests"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <OtherUnitFiles Value="../src"/> <UnitOutputDirectory Value="../lib/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> <UseAnsiStrings Value="False"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <RangeChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> <VerifyObjMethodCallValidity Value="True"/> </CodeGeneration> <Linking> <Debugging> <DebugInfoType Value="dsDwarf2Set"/> <UseHeaptrc Value="True"/> <TrashVariables Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="5"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> <Item4> <Name Value="EChakraCore"/> </Item4> <Item5> <Name Value="EChakraCoreScript"/> </Item5> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: tests/ChakraCoreTestsUI.XE.dproj ================================================  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <ProjectGuid>{0BA6D13A-3E85-4F64-897A-C3478268B7F8}</ProjectGuid> <MainSource>ChakraCoreTestsUI.dpr</MainSource> <Config Condition="'$(Config)'==''">Debug</Config> <DCC_DCCCompiler>DCC32</DCC_DCCCompiler> <ProjectVersion>12.3</ProjectVersion> <Base>True</Base> <Platform>Win32</Platform> <AppType>Console</AppType> <FrameworkType>None</FrameworkType> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> <Cfg_1>true</Cfg_1> <CfgParent>Base</CfgParent> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> <Cfg_2>true</Cfg_2> <CfgParent>Base</CfgParent> <Base>true</Base> </PropertyGroup> <PropertyGroup Condition="'$(Base)'!=''"> <DCC_DependencyCheckOutputName>..\bin\$(Platform)\$(Config)\ChakraCoreTestsUI.exe</DCC_DependencyCheckOutputName> <DCC_ExeOutput>..\bin\$(Platform)\$(Config)</DCC_ExeOutput> <DCC_DcuOutput>..\lib\$(Platform)\$(Config)</DCC_DcuOutput> <DCC_ImageBase>00400000</DCC_ImageBase> <DCC_UsePackage>vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers</DCC_UsePackage> <DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias)</DCC_UnitAlias> <DCC_Platform>x86</DCC_Platform> <DCC_UnitSearchPath>..\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> <DCC_K>false</DCC_K> <DCC_N>true</DCC_N> <DCC_S>false</DCC_S> <DCC_SymbolReferenceInfo>1</DCC_SymbolReferenceInfo> <DCC_E>false</DCC_E> <DCC_F>false</DCC_F> </PropertyGroup> <PropertyGroup Condition="'$(Cfg_1)'!=''"> <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> <DCC_DebugInformation>false</DCC_DebugInformation> </PropertyGroup> <PropertyGroup Condition="'$(Cfg_2)'!=''"> <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> </PropertyGroup> <ItemGroup> <DelphiCompile Include="ChakraCoreTestsUI.dpr"> <MainSource>MainSource</MainSource> </DelphiCompile> <BuildConfiguration Include="Debug"> <Key>Cfg_2</Key> <CfgParent>Base</CfgParent> </BuildConfiguration> <BuildConfiguration Include="Base"> <Key>Base</Key> </BuildConfiguration> <BuildConfiguration Include="Release"> <Key>Cfg_1</Key> <CfgParent>Base</CfgParent> </BuildConfiguration> </ItemGroup> <Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/> <Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/> <ProjectExtensions> <Borland.Personality>Delphi.Personality.12</Borland.Personality> <Borland.ProjectType>VCLApplication</Borland.ProjectType> <BorlandProject> <Delphi.Personality> <Source> <Source Name="MainSource">ChakraCoreTestsUI.dpr</Source> </Source> <Parameters/> <VersionInfo> <VersionInfo Name="IncludeVerInfo">True</VersionInfo> <VersionInfo Name="AutoIncBuild">False</VersionInfo> <VersionInfo Name="MajorVer">1</VersionInfo> <VersionInfo Name="MinorVer">0</VersionInfo> <VersionInfo Name="Release">0</VersionInfo> <VersionInfo Name="Build">0</VersionInfo> <VersionInfo Name="Debug">False</VersionInfo> <VersionInfo Name="PreRelease">False</VersionInfo> <VersionInfo Name="Special">False</VersionInfo> <VersionInfo Name="Private">False</VersionInfo> <VersionInfo Name="DLL">False</VersionInfo> <VersionInfo Name="Locale">1033</VersionInfo> <VersionInfo Name="CodePage">1252</VersionInfo> </VersionInfo> <VersionInfoKeys> <VersionInfoKeys Name="CompanyName"/> <VersionInfoKeys Name="FileDescription"/> <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="InternalName">ChakraCoreTestsUI</VersionInfoKeys> <VersionInfoKeys Name="LegalCopyright">© 2021 Ondrej Kelle</VersionInfoKeys> <VersionInfoKeys Name="LegalTrademarks"/> <VersionInfoKeys Name="OriginalFilename">ChakraCoreTestsUI</VersionInfoKeys> <VersionInfoKeys Name="ProductName">chakracore-delphi</VersionInfoKeys> <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> <VersionInfoKeys Name="Comments"/> </VersionInfoKeys> </Delphi.Personality> <Platforms> <Platform value="Win32">True</Platform> </Platforms> </BorlandProject> <ProjectFileVersion>12</ProjectFileVersion> </ProjectExtensions> </Project> ================================================ FILE: tests/ChakraCoreTestsUI.dof ================================================ [FileVersion] Version=7.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; NamespacePrefix= SymbolDeprecated=1 SymbolLibrary=1 SymbolPlatform=1 UnitLibrary=1 UnitPlatform=1 UnitDeprecated=1 HResultCompat=1 HidingMember=1 HiddenVirtual=1 Garbage=1 BoundsError=1 ZeroNilCompat=1 StringConstTruncated=1 ForLoopVarVarPar=1 TypedConstVarPar=1 AsgToTypedConst=1 CaseLabelRange=1 ForVariable=1 ConstructingAbstract=1 ComparisonFalse=1 ComparisonTrue=1 ComparingSignedUnsigned=1 CombiningSignedUnsigned=1 UnsupportedConstruct=1 FileOpen=1 FileOpenUnitSrc=1 BadGlobalSymbol=1 DuplicateConstructorDestructor=1 InvalidDirective=1 PackageNoLink=1 PackageThreadVar=1 ImplicitImport=1 HPPEMITIgnored=1 NoRetVal=1 UseBeforeDef=1 ForLoopVarUndef=1 UnitNameMismatch=1 NoCFGFileFound=1 MessageDirective=1 ImplicitVariants=1 UnicodeToLocale=1 LocaleToUnicode=1 ImagebaseMultiple=1 SuspiciousTypecast=1 PrivatePropAccessor=1 UnsafeType=0 UnsafeCode=0 UnsafeCast=0 [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir=..\bin\Win32\Debug UnitOutputDir=..\lib\Win32\Debug PackageDLLOutputDir= PackageDCPOutputDir= SearchPath=..\src Packages=vcl;rtl;vclx;indy;inet;xmlrtl;vclie;inetdbbde;inetdbxpress;dbrtl;dsnap;dsnapcon;vcldb;soaprtl;VclSmp;dbexpress;dbxcds;inetdb;bdertl;vcldbx;webdsnap;websnap;adortl;ibxpress;teeui;teedb;tee;dss;visualclx;visualdbclx;vclactnband;vclshlctrls;IntrawebDB_50_70;Intraweb_50_70;Rave50CLX;Rave50VCL;dclOfficeXP;JclDeveloperTools;Jcl;JclVcl;JclContainers Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Language] ActiveLang= ProjectLang= RootDir= [Version Info] IncludeVerInfo=1 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1033 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName=ChakraCoreTestsUI LegalCopyright=� 2021 Ondrej Kelle LegalTrademarks= OriginalFilename=ChakraCoreTestsUI.exe ProductName=chakracore-delphi ProductVersion=1.0.0.0 [HistoryLists\hlUnitAliases] Count=1 Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [HistoryLists\hlSearchPath] Count=1 Item0=..\..\src [HistoryLists\hlUnitOutputDirectory] Count=1 Item0=..\..\lib\Win32\Debug [HistoryLists\hlOutputDirectorry] Count=1 Item0=..\..\bin\Win32\Debug ================================================ FILE: tests/ChakraCoreTestsUI.dpr ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) program ChakraCoreTestsUI; {$include ..\src\common.inc} {$ifdef FPC} {$apptype GUI} {$endif} uses SysUtils, Classes, {$ifdef FPC} Interfaces, Forms, Graphics, GuiTestRunner, {$endif} {$ifdef DELPHI} TestFramework, GUITestRunner, {$endif} Compat, Test_ChakraCore, Test_Classes, ChakraCoreVersion; {$R *.res} begin {$ifdef FPC} Application.Initialize; Application.CreateForm(TGuiTestRunner, TestRunner); {$ifdef WINDOWS} TestRunner.XMLSynEdit.Font.Name := 'Consolas'; {$endif} {$ifdef LINUX} TestRunner.XMLSynEdit.Font.Name := 'Liberation Mono'; {$endif} {$ifdef DARWIN} TestRunner.XMLSynEdit.Font.Name := 'Menlo'; {$endif} TestRunner.XMLSynEdit.Font.Quality := fqCleartype; TestRunner.MemoLog.Append(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); TestRunner.MemoLog.Append(Format('Built with %s', [GetBuildInfoString])); TestRunner.MemoLog.Append(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); Application.Run; {$endif} {$ifdef DELPHI} with TGUITestRunner.Create(nil) do begin try ErrorMessageRTF.Lines.Add(Format('%s %s', [ExtractFileName(ParamStr(0)), GetExeFileVersionString])); ErrorMessageRTF.Lines.Add(Format('Built with %s', [GetBuildInfoString])); ErrorMessageRTF.Lines.Add(Format('Chakra Core version: %d.%d.%d', [CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION])); Suite := registeredTests; ShowModal; finally Free; end; end; {$endif} end. ================================================ FILE: tests/ChakraCoreTestsUI.lpi ================================================ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> <Version Value="11"/> <General> <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="ChakraCoreTestsUI"/> <ResourceType Value="res"/> <UseXPManifest Value="True"/> </General> <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="1"/> <StringTable InternalName="ChakraCoreTestsUI" LegalCopyright="© 2021 Ondrej Kelle" OriginalFilename="ChakraCoreTestsUI" ProductName="chakracore-delphi"/> </VersionInfo> <BuildModes Count="2"> <Item1 Name="Debug" Default="True"/> <Item2 Name="Release"> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)/ChakraCoreTestsUI"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <Libraries Value="../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> <OtherUnitFiles Value="../src;$(LazarusDir)/components/fpcunit/lib/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);$(LazarusDir)/components/fpcunit"/> <UnitOutputDirectory Value="../lib/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> <Optimizations> <OptimizationLevel Value="3"/> </Optimizations> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> </Debugging> <LinkSmart Value="True"/> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> </CompilerOptions> </Item2> </BuildModes> <PublishOptions> <Version Value="2"/> </PublishOptions> <RunParams> <FormatVersion Value="2"/> <Modes Count="1"> <Mode0 Name="default"/> </Modes> </RunParams> <RequiredPackages Count="3"> <Item1> <PackageName Value="fpcunittestrunner"/> </Item1> <Item2> <PackageName Value="LCL"/> </Item2> <Item3> <PackageName Value="FCL"/> </Item3> </RequiredPackages> <Units Count="3"> <Unit0> <Filename Value="ChakraCoreTestsUI.dpr"/> <IsPartOfProject Value="True"/> </Unit0> <Unit1> <Filename Value="Test_ChakraCore.pas"/> <IsPartOfProject Value="True"/> </Unit1> <Unit2> <Filename Value="Test_Classes.pas"/> <IsPartOfProject Value="True"/> </Unit2> </Units> </ProjectOptions> <CompilerOptions> <Version Value="11"/> <Target> <Filename Value="../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)/ChakraCoreTestsUI"/> </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> <Libraries Value="../bin/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> <OtherUnitFiles Value="../src;$(LazarusDir)/components/fpcunit/lib/$(TargetCPU)-$(TargetOS)/$(LCLWidgetType);$(LazarusDir)/components/fpcunit"/> <UnitOutputDirectory Value="../lib/$(TargetCPU)-$(TargetOS)/$(BuildMode)"/> </SearchPaths> <Parsing> <SyntaxOptions> <SyntaxMode Value="Delphi"/> <IncludeAssertionCode Value="True"/> </SyntaxOptions> </Parsing> <CodeGeneration> <Checks> <IOChecks Value="True"/> <OverflowChecks Value="True"/> <StackChecks Value="True"/> </Checks> </CodeGeneration> <Linking> <Options> <Win32> <GraphicApplication Value="True"/> </Win32> </Options> </Linking> </CompilerOptions> <Debugging> <Exceptions Count="5"> <Item1> <Name Value="EAbort"/> </Item1> <Item2> <Name Value="ECodetoolError"/> </Item2> <Item3> <Name Value="EFOpenError"/> </Item3> <Item4> <Name Value="EChakraCore"/> </Item4> <Item5> <Name Value="EChakraCoreScript"/> </Item5> </Exceptions> </Debugging> </CONFIG> ================================================ FILE: tests/Test_ChakraCore.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit Test_ChakraCore; interface {$include ..\src\common.inc} uses Classes, SysUtils, {$ifdef FPC} {$ifndef WINDOWS} cwstring, {$endif} fpcunit, testregistry, {$else} TestFramework, {$endif} Compat, ChakraCoreVersion, ChakraCommon, ChakraCore, ChakraDebug, ChakraCoreUtils; type { TBaseTestCase } TBaseTestCase = class(TTestCase) public {$ifdef DELPHI} // work around Delphi 2007 and earlier compiler error "Ambiguous overloaded call to 'CheckEquals'" procedure CheckEquals(expected, actual: Integer; msg: string = ''); override; // DUnit needs a delta when comparing float values procedure CheckEquals(expected, actual: extended; msg: string = ''); reintroduce; overload; {$endif} procedure CheckEquals(expected, actual: JsValueType; const msg: string = ''); overload; procedure CheckEquals(expected, actual: JsTypedArrayType; const msg: string = ''); overload; procedure CheckValueType(expected: JsValueType; value: JsValueRef; const msg: string = ''); end; TChakraCoreTestCase = class(TBaseTestCase) private FContext: JsContextRef; FRuntime: JsRuntimeHandle; protected procedure SetUp; override; procedure TearDown; override; end; TChakraCoreUtilsScripting = class(TChakraCoreTestCase) published procedure TestVersion; procedure TestUndefined; procedure TestNull; procedure TestInt; procedure TestDouble; procedure TestInfinity; procedure TestNaN; procedure TestString; procedure TestStringUnicode; procedure TestBoolean; procedure TestObject; procedure TestFunction; procedure TestError; procedure TestArray; procedure TestSymbol; procedure TestArrayBuffer; procedure TestTypedArray; procedure TestDataView; procedure TestThrowBoolean; procedure TestThrowInt; procedure TestThrowString; procedure TestThrowObject; procedure TestThrowError; procedure TestThrowHostError; procedure TestCallFunction01; procedure TestCallFunction02; procedure TestCallFunction03; procedure TestCallFunctions; procedure TestCallNew; procedure TestFPExceptions; procedure TestDebugging; end; { TChakraCorePrototypes } TChakraCorePrototypes = class(TChakraCoreTestCase) published procedure TestInheritance; end; implementation uses {$ifdef HAS_WIDESTRUTILS} WideStrUtils, {$endif} Math; {$ifdef DELPHI} procedure TBaseTestCase.CheckEquals(expected, actual: Integer; msg: string); begin inherited CheckEquals(expected, actual, msg); end; procedure TBaseTestCase.CheckEquals(expected, actual: extended; msg: string); const DefaultDelta = 0.0000001; begin inherited CheckEquals(expected, actual, DefaultDelta, msg); end; {$endif} procedure TBaseTestCase.CheckEquals(expected, actual: JsValueType; const msg: string); begin inherited CheckEquals(Ord(expected), Ord(actual), msg); end; procedure TBaseTestCase.CheckEquals(expected, actual: JsTypedArrayType; const msg: string); begin inherited CheckEquals(Ord(expected), Ord(actual), msg); end; procedure TBaseTestCase.CheckValueType(expected: JsValueType; value: JsValueRef; const msg: string); begin CheckEquals(expected, JsGetValueType(Value), msg); end; procedure TChakraCoreTestCase.SetUp; begin FRuntime := nil; FContext := nil; ChakraCoreCheck(JsCreateRuntime(JsRuntimeAttributeNone, nil, FRuntime)); ChakraCoreCheck(JsCreateContext(FRuntime, FContext)); ChakraCoreCheck(JsSetCurrentContext(FContext)); end; procedure TChakraCoreTestCase.TearDown; begin ChakraCoreCheck(JsSetCurrentContext(JS_INVALID_REFERENCE)); if Assigned(FRuntime) then ChakraCoreCheck(JsDisposeRuntime(FRuntime)); end; procedure TChakraCoreUtilsScripting.TestVersion; begin CheckEquals(Integer(1), CHAKRA_CORE_MAJOR_VERSION, 'major version number'); CheckEquals(Integer(11), CHAKRA_CORE_MINOR_VERSION, 'minor version number'); CheckEquals(Integer(24), CHAKRA_CORE_PATCH_VERSION, 'patch version number'); end; procedure TChakraCoreUtilsScripting.TestUndefined; const SScript = 'this.result = undefined'; SName = 'TestUndefined.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsUndefined, Result, 'result type'); Check(JsEqual(JsUndefinedValue, Result, True), 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestNull; const SScript = 'this.result = null'; SName = 'TestNull.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsNull, Result, 'result type'); Check(JsEqual(JsNullValue, Result, True), 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestInt; const IntValue = 42; SScript = 'this.result = %d'; SName = 'TestInt.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(Format(SScript, [IntValue])), UnicodeString(SName)) else Result := JsRunScript(UTF8String(Format(SScript, [IntValue])), UTF8String(SName)); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(IntValue, JsNumberToInt(Result), 'result value'); Check(JsEqual(IntToJsNumber(IntValue), Result, True), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestDouble; const DoubleValue: Double = 3.14; SScript = 'this.result = %f'; SName = 'TestDouble.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False To True do begin if Unicode then Result := JsRunScript(UnicodeString(Format(SScript, [DoubleValue], DefaultFormatSettings)), UnicodeString(SName)) else Result := JsRunScript(UTF8String(Format(SScript, [DoubleValue], DefaultFormatSettings)), UTF8String(SName)); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(DoubleValue, JsNumberToDouble(Result), 'result value'); Check(JsEqual(DoubleToJsNumber(DoubleValue), Result, True), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestInfinity; const SScript = 'this.result = Infinity'; SName = 'TestInfinity.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsNumber, Result, 'result type'); Check(IsInfinite(JsNumberToDouble(Result)), 'INF'); end; end; procedure TChakraCoreUtilsScripting.TestNaN; const SScript = 'this.result = NaN'; SName = 'TestNaN.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsNumber, Result, 'result type'); Check(IsNan(JsNumberToDouble(Result)), 'NaN'); end; end; procedure TChakraCoreUtilsScripting.TestString; const StringValues: array[0..1] of UnicodeString = ('', 'Hello, world!'); SScript = 'this.result = "%s"'; SName = 'TestString.js'; var Unicode: Boolean; I: Integer; Result: JsValueRef; begin for Unicode := False to True do for I := Low(StringValues) to High(StringValues) do begin if Unicode then Result := JsRunScript(UnicodeString(Format(SScript, [StringValues[I]])), UnicodeString(SName)) else Result := JsRunScript(UTF8String(Format(SScript, [StringValues[I]])), UTF8String(SName)); CheckValueType(JsString, Result, 'result type'); CheckEquals(StringValues[I], JsStringToUnicodeString(Result), 'result value'); Check(JsEqual(StringToJsString(StringValues[I]), Result, True), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestStringUnicode; const StringValues: array [0..1] of UTF8String = ('', #$E4#$BD#$A0#$E5#$A5#$BD); SScript = 'this.result = "%s"'; SName = 'TestString.js'; var Unicode: Boolean; I: Integer; Result: JsValueRef; begin for Unicode := False to True do for I := Low(StringValues) to High(StringValues) do begin if Unicode then Result := JsRunScript(WideFormat(SScript, [UTF8ToString(StringValues[I])]), UnicodeString(SName)) else Result := JsRunScript(Format(SScript, [UTF8String(StringValues[I])]), UTF8String(SName)); CheckValueType(JsString, Result, 'result type'); {$ifdef SUPPORTS_UNICODE} CheckEquals(UTF8ToString(StringValues[I]), JsStringToUnicodeString(Result), 'result value'); {$else} CheckEquals(UTF8String(StringValues[I]), JsStringToUTF8String(Result), 'result value'); {$endif} Check(JsEqual(StringToJsString(StringValues[I]), Result, True), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestBoolean; const SScripts: array[Boolean] of string = ( 'this.result = false', 'this.result = true' ); SName = 'TestBoolean.js'; var Unicode, BooleanValue: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin for BooleanValue := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScripts[BooleanValue]), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScripts[BooleanValue]), UTF8String(SName)); CheckValueType(JsBoolean, Result, 'result type'); CheckEquals(BooleanValue, JsBooleanToBoolean(Result), 'result value'); Check(JsEqual(BooleanToJsBoolean(BooleanValue), Result, True), 'result value'); end; end; end; procedure TChakraCoreUtilsScripting.TestObject; const SScript = 'this.result = this'; SName = 'TestObject.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsObject, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestFunction; const SScript = 'this.result = function() { return 42; }'; SName = 'TestFunction.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsFunction, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestError; const SScript = 'this.result = new Error("Test Error")'; SName = 'TestError.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsError, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestArray; const IntElementValue = 42; DoubleElementValue = 3.14; StringElementValue: UnicodeString = 'Hello, world!'; SScript = 'this.result = [undefined, null, %d, %f, "%s", true, false, this, function() { return 42; }, new Error("Test Error")]'; SName = 'TestArray.js'; var Unicode: Boolean; Result, Element: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(Format(SScript, [IntElementValue, DoubleElementValue, StringElementValue], DefaultFormatSettings)), UnicodeString(SName)) else Result := JsRunScript(UTF8String(Format(SScript, [IntElementValue, DoubleElementValue, StringElementValue], DefaultFormatSettings)), UTF8String(SName)); CheckValueType(JsArray, Result, 'result type'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(0), Element)); CheckValueType(JsUndefined, Element, 'element 0 type'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(1), Element)); CheckValueType(JsNull, Element, 'element 1 type'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(2), Element)); CheckValueType(JsNumber, Element, 'element 2 type'); CheckEquals(IntElementValue, JsNumberToInt(Element), 'element 2 value'); Check(JsEqual(IntToJsNumber(IntElementValue), Element, True), 'element 2 value'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(3), Element)); CheckValueType(JsNumber, Element, 'element 3 type'); CheckEquals(DoubleElementValue, JsNumberToDouble(Element), 'element 3 value'); Check(JsEqual(DoubleToJsNumber(DoubleElementValue), Element, True), 'element 3 value'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(4), Element)); CheckValueType(JsString, Element, 'element 4 type'); CheckEquals(StringElementValue, JsStringToUnicodeString(Element), 'element 4 value'); Check(JsEqual(StringToJsString(StringElementValue), Element, True), 'element 4 value'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(5), Element)); CheckValueType(JsBoolean, Element, 'element 5 type'); CheckEquals(True, JsBooleanToBoolean(Element), 'element 5 value'); Check(JsEqual(BooleanToJsBoolean(True), Element, True), 'element 5 value'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(6), Element)); CheckValueType(JsBoolean, Element, 'element 6 type'); CheckEquals(False, JsBooleanToBoolean(Element), 'element 6 value'); Check(JsEqual(BooleanToJsBoolean(False), Element, True), 'element 6 value'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(7), Element)); CheckValueType(JsObject, Element, 'element 7 type'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(8), Element)); CheckValueType(JsFunction, Element, 'element 8 type'); ChakraCoreCheck(JsGetIndexedProperty(Result, IntToJsNumber(9), Element)); CheckValueType(JsError, Element, 'element 9 type'); end; end; procedure TChakraCoreUtilsScripting.TestSymbol; const SScript = 'this.result = Symbol(''foo'')'; SName = 'TestSymbol.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsSymbol, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestArrayBuffer; const SScript = 'this.result = new ArrayBuffer(1024)'; SName = 'TestArrayBuffer.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsArrayBuffer, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestTypedArray; const SScripts: array[JsTypedArrayType] of string = ( 'this.result = new Int8Array(16)', 'this.result = new Uint8Array(16)', 'this.result = new Uint8ClampedArray(16)', 'this.result = new Int16Array(16)', 'this.result = new Uint16Array(16)', 'this.result = new Int32Array(16)', 'this.result = new Uint32Array(16)', 'this.result = new Float32Array(16)', 'this.result = new Float64Array(16)' ); SName = 'TesTypedtArray.js'; var Unicode: Boolean; I: JsTypedArrayType; Result: JsValueRef; begin for Unicode := False to True do begin for I := Low(JsTypedArraytype) to High(JsTypedArraytype) do begin if Unicode then Result := JsRunScript(UnicodeString(SScripts[I]), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScripts[I]), UTF8String(SName)); CheckValueType(JsTypedArray, Result, 'result type'); CheckEquals(I, JsGetTypedArrayType(Result), 'element type'); end; end; end; procedure TChakraCoreUtilsScripting.TestDataView; const SScript = 'this.result = new DataView(new ArrayBuffer(1024), 0, 1024)'; SName = 'TestArrayBuffer.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsDataView, Result, 'result type'); end; end; procedure TChakraCoreUtilsScripting.TestThrowBoolean; const SScript = 'throw true;'; SName = 'TestThrowBoolean.js'; var Unicode: Boolean; begin for Unicode := False to True do begin try if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValueType(JsBoolean, E.Error, 'error type'); CheckEquals(True, JsBooleanToBoolean(E.Error), 'error value'); end; end; end; end; procedure TChakraCoreUtilsScripting.TestThrowInt; const IntValue = 42; SScript = 'throw %d;'; SName = 'TestThrowInt.js'; var Unicode: Boolean; begin for Unicode := False to True do begin try if Unicode then JsRunScript(UnicodeString(Format(SScript, [IntValue])), UnicodeString(SName)) else JsRunScript(UTF8String(Format(SScript, [IntValue])), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValuetype(JsNumber, E.Error, 'error type'); CheckEquals(IntValue, JsNumberToInt(E.Error), 'error value'); end; end; end; end; procedure TChakraCoreUtilsScripting.TestThrowString; const StringValue: UnicodeString = 'Error'; SScript = 'throw "%s";'; SName = 'TestThrowString.js'; var Unicode: Boolean; begin for Unicode := False to True do begin try if Unicode then JsRunScript(UnicodeString(Format(SScript, [StringValue])), UnicodeString(SName)) else JsRunScript(UTF8String(Format(SScript, [StringValue])), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValueType(JsString, E.Error, 'error type'); CheckEquals(StringValue, JsStringToUnicodeString(E.Error)); end; end; end; end; procedure TChakraCoreUtilsScripting.TestThrowObject; const SScript = 'throw this;'; SName = 'TestThrowObject.js'; var Unicode: Boolean; begin for Unicode := False to True do begin try if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValueType(JsObject, E.Error, 'error type'); end; end; end; end; procedure TChakraCoreUtilsScripting.TestThrowError; const SScript = 'syntax error?'; SName = 'TestThrowError.js'; var Unicode: Boolean; Name, Message: JsValueRef; begin for Unicode := False to True do begin try if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValueType(JsError, E.Error, 'error type'); Name := JsGetProperty(E.Error, 'name'); Message := JsGetProperty(E.Error, 'message'); CheckEquals(UnicodeString('SyntaxError'), JsStringToUnicodeString(Name)); CheckEquals(UnicodeString('Expected '';'''), JsStringToUnicodeString(Message)); end; end; end; end; const ErrorTypeNames: array[TErrorType] of UnicodeString = ('Error', 'RangeError', 'ReferenceError', 'SyntaxError', 'TypeError', 'URIError'); type PErrorType = ^TErrorType; function TestErrorCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var ErrorType: PErrorType absolute CallbackState; begin ChakraCoreCheck(JsGetUndefinedValue(Result)); JsThrowError(Format('Test %s error', [ErrorTypeNames[ErrorType^]]), ErrorType^); end; procedure TChakraCoreUtilsScripting.TestThrowHostError; const SScript = 'this.testerror();'; SName = 'TestThrowHostError.js'; var Global: JsValueRef; Unicode: Boolean; EType: TErrorType; Name, Message: JsValueRef; begin ChakraCoreCheck(JsGetGlobalObject(Global)); JsSetCallback(Global, 'testerror', @TestErrorCallback, @EType); for Unicode := False to True do begin for EType := Low(TErrorType) to High(TErrorType) do begin try if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Check(False, 'Expected error'); except on E: EChakraCore do begin CheckValueType(JsError, E.Error, 'error type'); Name := JsGetProperty(E.Error, 'name'); Message := JsGetProperty(E.Error, 'message'); CheckEquals(ErrorTypeNames[EType], JsStringToUnicodeString(Name)); CheckEquals(WideFormat('Test %s error', [ErrorTypeNames[EType]]), JsStringToUnicodeString(Message)); end; end; end; end; end; procedure TChakraCoreUtilsScripting.TestCallFunction01; const SScript = 'function square(number) { return number * number; }'; SName = 'TestCallFunction01.js'; var Unicode: Boolean; Result: JsValueRef; Global, SquareFunc: JsValueRef; begin for Unicode := False to True do begin if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); ChakraCoreCheck(JsGetGlobalObject(Global)); SquareFunc := JsGetProperty(Global, 'square'); Result := JsCallFunction(SquareFunc, [IntToJsNumber(3)]); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(9, JsNumberToInt(Result), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestCallFunction02; const SScript = 'function square(number) { return number * number; }'; SName = 'TestCallFunction02.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Result := JsCallFunction('square', [IntToJsNumber(3)]); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(9, JsNumberToInt(Result), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestCallFunction03; const SScript = 'var obj = {}; obj.square = function square(number) { return number * number; }'; SName = 'TestCallFunction02.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else JsRunScript(UTF8String(SScript), UTF8String(SName)); Result := JsCallFunction('square', [IntToJsNumber(3)], JsGetProperty(JsGlobal, UnicodeString('obj'))); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(9, JsNumberToInt(Result), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestCallFunctions; const SScript1 = 'function square(number) { return number * number; }'; SScript2 = 'function fact(number) { if (number == 0) { return 1; } else { return number * fact(number - 1); } }'; SName = 'TestCallFunctions.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then begin Result := JsRunScript(UnicodeString(SScript1), UnicodeString(SName)); CheckValueType(JsUndefined, Result, 'result type'); Result := JsRunScript(UnicodeString(SScript2), UnicodeString(SName)); CheckValueType(JsUndefined, Result, 'result type'); end else begin Result := JsRunScript(UTF8String(SScript1), UTF8String(SName)); CheckValueType(JsUndefined, Result, 'result type'); Result := JsRunScript(UTF8String(SScript2), UTF8String(SName)); CheckValueType(JsUndefined, Result, 'result type'); end; Result := JsCallFunction('square', [IntToJsNumber(3)]); CheckValuetype(JsNumber, Result, 'result type'); CheckEquals(9, JsNumberToInt(Result), 'result value'); Result := JsCallFunction('fact', [IntToJsNumber(5)]); CheckValueType(JsNumber, Result, 'result type'); CheckEquals(120, JsNumberToInt(Result), 'result value'); end; end; procedure TChakraCoreUtilsScripting.TestCallNew; const SScript = 'this.result = new Object()'; SName = 'TestCallNew.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsObject, Result, 'result type'); Check(JsInstanceOf(Result, 'Object'), 'instanceof Object'); end; end; procedure TChakraCoreUtilsScripting.TestFPExceptions; const SScript = 'var d = new Date(); this.Result = d.getTime();'; SName = 'TestFPExceptions.js'; var Unicode: Boolean; Result: JsValueRef; begin for Unicode := False to True do begin if Unicode then Result := JsRunScript(UnicodeString(SScript), UnicodeString(SName)) else Result := JsRunScript(UTF8String(SScript), UTF8String(SName)); CheckValueType(JsNumber, Result, 'result type'); end; end; function DebugCallback(debugEvent: JsDiagDebugEvent; eventData: JsValueRef; callbackState: Pointer): JsErrorCode; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := JsNoError; end; procedure TChakraCoreUtilsScripting.TestDebugging; var Dummy: Pointer; begin Check(not JsIsDebugging, 'is debugging'); ChakraCoreCheck(JsDiagStartDebugging(FRuntime, DebugCallback, nil)); try Check(JsIsDebugging, 'is debugging'); finally ChakraCoreCheck(JsDiagStopDebugging(FRuntime, @Dummy)); end; Check(not JsIsDebugging, 'is debugging'); end; { TChakraCorePrototypes } var RectangleConstructor: JsValueRef = nil; RectanglePrototype: JsValueref = nil; function Rectangle_ConstructorCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var TestCase: TChakraCorePrototypes absolute CallbackState; ArgsArray: PJsValueRefArray absolute Args; ShapeCtr: JsValueRef; begin Result := JsUndefinedValue; try TestCase.CheckValueType(JsFunction, Callee, 'Rectangle constructor value type'); TestCase.CheckEquals(5, Integer(ArgCount), 'Rectangle constructor argument count'); ShapeCtr := JsGetProperty(JsGlobal, 'Shape'); if IsConstructCall then ChakraCoreCheck(JsCreateExternalObjectWithPrototype(CallbackState, nil, RectanglePrototype, Result)) else Result := ArgsArray^[0]; // Shape.call(x, y); JsCallFunction(ShapeCtr, [ArgsArray^[1], ArgsArray^[2]], Result); // this.w = w; JsSetProperty(Result, UnicodeString('w'), ArgsArray^[3]); // this.h = h; JsSetProperty(Result, UnicodeString('h'), ArgsArray^[4]); except on E: Exception do JsThrowError(Format('[%s] %s', [E.ClassName, E.Message])); end; end; function Global_GetRectangleCallback(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} var ShapeCtr, ShapePrototype: JsValueRef; begin Result := JsUndefinedValue; try if not Assigned(RectangleConstructor) then begin ChakraCoreCheck(JsCreateNamedFunction(StringToJsString('Rectangle'), Rectangle_ConstructorCallback, CallbackState, RectangleConstructor)); end; if not Assigned(RectanglePrototype) then begin ShapeCtr := JsGetProperty(JsGlobal, 'Shape'); ShapePrototype := JsGetProperty(ShapeCtr, 'prototype'); // Rectangle.prototype = Object.create(Shape.prototype); RectanglePrototype := JsCreateObject(ShapePrototype); JsSetProperty(RectangleConstructor, 'prototype', RectanglePrototype); // Rectangle.prototype.constructor = Rectangle; JsSetProperty(RectanglePrototype, 'constructor', RectangleConstructor); end; Result := RectangleConstructor; except on E: Exception do JsThrowError(Format('[%s] %s', [E.ClassName, E.Message])); end; end; procedure TChakraCorePrototypes.TestInheritance; // - Shape (x, y) => Object // - Circle (x, y, r) => Shape (x, y) // - Rectangle (x, y, w, h) => Shape (x, y) // - Square (x, y, w) => Rectangle (x, y, w, w) const SScript = // Shape: (Javascript) superclass 'function Shape(x, y) {' + sLineBreak + ' this.x = x;' + sLineBreak + ' this.y = y;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Shape.prototype.move = function(x, y) {' + sLineBreak + ' this.x += x;' + sLineBreak + ' this.y += y;' + sLineBreak + '};' + sLineBreak + sLineBreak + // Circle: (Javascript) subclass of (Javascript) Shape 'function Circle(x, y, r) {' + sLineBreak + ' Shape.call(this, x, y);' + sLineBreak + ' this.r = r;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Circle.prototype = Object.create(Shape.prototype);' + sLineBreak + 'Circle.prototype.constructor = Circle;' + sLineBreak + sLineBreak + // Square: (Javascript) subclass of (native) Rectangle 'function Square(x, y, w) {' + sLineBreak + ' Rectangle.call(this, x, y, w, w);' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Square.prototype = Object.create(Rectangle.prototype);' + sLineBreak + 'Square.prototype.constructor = Square;'; SName = 'TestInheritance.js'; var ShapeObj, CircleObj, RectangleObj, SquareObj: JsValueRef; begin RectangleConstructor := nil; RectanglePrototype := nil; try JsDefineProperty('Rectangle', True, True, JsCreateFunction(Global_GetRectangleCallback, Self, UnicodeString('')), nil, JsGlobal); JsRunScript(SScript, SName); // var shapeObj = new Shape(10, 10); ShapeObj := JsNew('Shape', [IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, ShapeObj, 'shapeObj value type'); CheckTrue(JsInstanceOf(ShapeObj, 'Shape'), 'shapeObj instanceof Shape'); CheckFalse(JsInstanceOf(ShapeObj, 'Circle'), 'shapeObj instanceof Circle'); CheckFalse(JsInstanceOf(ShapeObj, 'Rectangle'), 'shapeObj instanceof Rectangle'); CheckFalse(JsInstanceOf(ShapeObj, 'Square'), 'shapeObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], ShapeObj); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y after move'); // var circleObj = new Circle(10, 10, 10); CircleObj := JsNew('Circle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, CircleObj, 'circleObj value type'); CheckTrue(JsInstanceOf(CircleObj, 'Shape'), 'circleObj instanceof Shape'); CheckTrue(JsInstanceOf(CircleObj, 'Circle'), 'circleObj instanceof Circle'); CheckFalse(JsInstanceOf(CircleObj, 'Rectangle'), 'circleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(CircleObj, 'Square'), 'circleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], CircleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y after move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r after move'); // var rectangleObj = new Rectangle(10, 10, 60, 40); RectangleObj := JsNew('Rectangle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(60), IntToJsNumber(40)]); CheckValueType(JsObject, RectangleObj, 'rectangleObj value type'); CheckTrue(JsInstanceOf(RectangleObj, 'Shape'), 'rectangleObj instanceof Shape'); CheckFalse(JsInstanceOf(RectangleObj, 'Circle'), 'rectangleObj instanceof Circle'); CheckTrue(JsInstanceOf(RectangleObj, 'Rectangle'), 'rectangleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(RectangleObj, 'Square'), 'rectangleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y before move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w before move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], RectangleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y after move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w after move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h after move'); // var squareObj = new Square(10, 10, 20); SquareObj := JsNew('Square', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(20)]); CheckValueType(JsObject, SquareObj, 'squareObj value type'); CheckTrue(JsInstanceOf(SquareObj, 'Shape'), 'squareObj instanceof Shape'); CheckFalse(JsInstanceOf(SquareObj, 'Circle'), 'squareObj instanceof Circle'); CheckTrue(JsInstanceOf(SquareObj, 'Rectangle'), 'squareObj instanceof Rectangle'); CheckTrue(JsInstanceOf(SquareObj, 'Square'), 'squareObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'sqaureObj.y before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], SquareObj); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'squareObj.y after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h after move'); finally RectanglePrototype := nil; RectangleConstructor := nil; end; end; initialization {$ifdef FPC} RegisterTests([TChakraCoreUtilsScripting, TChakraCorePrototypes]); {$else} RegisterTests([TChakraCoreUtilsScripting.Suite, TChakraCorePrototypes.Suite]); {$endif} end. ================================================ FILE: tests/Test_Classes.pas ================================================ (* MIT License Copyright (c) 2021 Ondrej Kelle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) unit Test_Classes; interface {$include ..\src\common.inc} uses Classes, SysUtils, {$ifdef FPC} {$ifndef WINDOWS} cwstring, {$endif} fpcunit, testregistry, {$else} TestFramework, {$endif} Compat, ChakraCommon, ChakraCore, ChakraCoreUtils, ChakraCoreClasses, Test_ChakraCore; type { TChakraCoreContextTestCase } TChakraCoreContextTestCase = class(TBaseTestCase) published procedure TestScriptReferenceError; procedure TestScriptSyntaxError; procedure TestEvalReferenceError; procedure TestEvalSyntaxError; end; { TNativeClassTestCase } TNativeClassTestCase = class(TBaseTestCase) published procedure TestMethod1AsScript; procedure TestMethod1AsFunction; procedure TestNamedProperty; procedure TestProjectedClass; procedure TestClassProjectedTwice; procedure TestClassProjectedInMultipleContexts; procedure TestInheritance; procedure TestInheritance2; procedure TestFinalizer; procedure TestFinalizer2; procedure TestFinalizer3; procedure TestFinalizer4; end; implementation { TChakraCoreContextTestCase } procedure TChakraCoreContextTestCase.TestScriptReferenceError; const SScript = 'badref.bla();'; SName = 'TestScriptReferenceError.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; try Context.RunScript(SScript, SName); except on E: EChakraCoreScript do begin CheckEquals(0, E.Line, 'EChakraCoreScript.Line'); CheckEquals(0, E.Column, 'EChakraCoreScript.Column'); CheckEquals(UnicodeString(SScript), E.Source, 'EChakraCoreScript.Source'); CheckEquals(UnicodeString(SName), E.ScriptURL, 'EChakraCoreScript.ScriptURL'); CheckEquals(LoadResString(JsGetErrorMessage(JsErrorScriptException)) + sLineBreak + 'ReferenceError: ''badref'' is not defined', E.Message, 'EChakraCoreScript.Message'); end; end; finally Context.Free; Runtime.Free; end; end; procedure TChakraCoreContextTestCase.TestScriptSyntaxError; const SScript: array[0..1] of UnicodeString = ( '// first line comment', ' @ bad syntax' ); SName = 'TestScriptSyntaxError.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; try Context.RunScript(SScript[0] + UnicodeString(sLineBreak) + SScript[1], UnicodeString(SName)); except on E: EChakraCoreScript do begin CheckEquals(1, E.Line, 'EChakraCoreScript.Line'); CheckEquals(3, E.Column, 'EChakraCoreScript.Column'); CheckEquals(SScript[1], E.Source, 'EChakraCoreScript.Source'); CheckEquals(UnicodeString(SName), E.ScriptURL, 'EChakraCoreScript.ScriptURL'); CheckEquals(LoadResString(JsGetErrorMessage(JsErrorScriptCompile)) + sLineBreak + 'SyntaxError: Invalid character', E.Message, 'EChakraCoreScript.Message'); end; end; finally Context.Free; Runtime.Free; end; end; procedure TChakraCoreContextTestCase.TestEvalReferenceError; const SScript = 'badref.bla();'; SName = 'TestEvalReferenceError.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; try Context.RunScript('eval(''' + SScript + ''');', SName); except on E: EChakraCoreScript do begin CheckEquals(0, E.Line, 'EChakraCoreScript.Line'); CheckEquals(0, E.Column, 'EChakraCoreScript.Column'); CheckEquals(UnicodeString(SScript), E.Source, 'EChakraCoreScript.Source'); CheckEquals(UnicodeString('eval code'), E.ScriptURL, 'EChakraCoreScript.ScriptURL'); CheckEquals(LoadResString(JsGetErrorMessage(JsErrorScriptException)) + sLineBreak + 'ReferenceError: ''badref'' is not defined', E.Message, 'EChakraCoreScript.Message'); end; end; finally Context.Free; Runtime.Free; end; end; procedure TChakraCoreContextTestCase.TestEvalSyntaxError; const SScript = 'eval(''@ bad syntax'');'; SName = 'TestEvalSyntaxError.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; try Context.RunScript(SScript, SName); except on E: EChakraCoreScript do begin CheckEquals(0, E.Line, 'EChakraCoreScript.Line'); CheckEquals(0, E.Column, 'EChakraCoreScript.Column'); CheckEquals(UnicodeString(SScript), E.Source, 'EChakraCoreScript.Source'); CheckEquals(UnicodeString(SName), E.ScriptURL, 'EChakraCoreScript.ScriptURL'); CheckEquals(LoadResString(JsGetErrorMessage(JsErrorScriptException)) + sLineBreak + 'SyntaxError: Invalid character', E.Message, 'EChakraCoreScript.Message'); end; end; finally Context.Free; Runtime.Free; end; end; { TTestObject1 } type TTestObject1 = class(TNativeObject) private FMethod1Called: Boolean; FProp1: UnicodeString; function GetProp1: JsValueRef; procedure SetProp1(Value: JsValueRef); function Method1(Args: PJsValueRef; ArgCount: Word): JsValueRef; protected class procedure RegisterProperties(AInstance: JsHandle); override; class procedure RegisterMethods(AInstance: JsHandle); override; end; function TTestObject1.GetProp1: JsValueRef; begin Result := StringToJsString(FProp1); end; procedure TTestObject1.SetProp1(Value: JsValueRef); var SValue: UnicodeString; begin SValue := JsStringToUnicodeString(Value); if SValue <> FProp1 then begin // Prop1 changed FProp1 := SValue; end; end; function TTestObject1.Method1(Args: PJsValueRef; ArgCount: Word): JsValueRef; begin Result := StringToJsString('Hello'); FMethod1Called := True; end; class procedure TTestObject1.RegisterMethods(AInstance: JsHandle); begin RegisterMethod(AInstance, 'method1', @TTestObject1.Method1); end; class procedure TTestObject1.RegisterProperties(AInstance: JsHandle); begin RegisterNamedProperty(AInstance, 'prop1', False, False, @TTestObject1.GetProp1, @TTestObject1.SetProp1); end; { TNativeClassTestCase } procedure TNativeClassTestCase.TestMethod1AsScript; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; TestObject: TTestObject1; Result: JsValueRef; begin Runtime := nil; Context := nil; TestObject := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TestObject := TTestObject1.Create; JsSetProperty(Context.Global, 'obj', TestObject.Instance); Result := Context.RunScript('obj.method1(null, null);', 'TestMethod1.js'); Check(TestObject.FMethod1Called, 'method1 called'); CheckValueType(JsString, Result, 'method1 result type'); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(Result), 'method1 result'); finally TestObject.Free; Context.Free; Runtime.Free; end; end; procedure TNativeClassTestCase.TestMethod1AsFunction; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; TestObject: TTestObject1; Result: JsValueRef; begin Runtime := nil; Context := nil; TestObject := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TestObject := TTestObject1.Create; JsSetProperty(Context.Global, 'obj', TestObject.Instance); Result := Context.CallFunction('method1', [], TestObject.Instance); Check(TestObject.FMethod1Called, 'method1 called'); CheckValueType(JsString, Result, 'method1 result type'); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(Result), 'method1 result'); finally TestObject.Free; Context.Free; Runtime.Free; end; end; procedure TNativeClassTestCase.TestNamedProperty; const SValue: UnicodeString = 'Hello'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; TestObject: TTestObject1; begin Runtime := nil; Context := nil; TestObject := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TestObject := TTestObject1.Create; JsSetProperty(Context.Global, 'obj', TestObject.Instance); Context.RunScript(WideFormat('obj.prop1 = ''%s'';', [SValue]), UnicodeString('TestNamedProperty.js')); CheckEquals(SValue, TestObject.FProp1, 'prop1 value'); CheckEquals(SValue, JsStringToUnicodeString(JsGetProperty(TestObject.Instance, 'prop1')), 'prop1 value'); finally TestObject.Free; Context.Free; Runtime.Free; end; end; procedure TNativeClassTestCase.TestProjectedClass; const SScript: UnicodeString = 'var obj = new TestObject(); var s1 = obj.method1(); obj.prop1 = s1; var s2 = obj.prop1;'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TTestObject1.Project('TestObject'); Context.RunScript(SScript, UnicodeString('TestProjectedClass.js')); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context.Global, 's1')), 's1'); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context.Global, 's2')), 's2'); finally Context.Free; Runtime.Free; end; end; procedure TNativeClassTestCase.TestClassProjectedTwice; begin TestProjectedClass; TestProjectedClass; end; procedure TNativeClassTestCase.TestClassProjectedInMultipleContexts; const SScript: UnicodeString = 'var obj = new TestObject(); var s1 = obj.method1(); obj.prop1 = s1; var s2 = obj.prop1;'; var Runtime: TChakraCoreRuntime; Context1, Context2: TChakraCoreContext; begin Runtime := nil; Context1 := nil; Context2 := nil; try Runtime := TChakraCoreRuntime.Create; Context1 := TChakraCoreContext.Create(Runtime); Context2 := TChakraCoreContext.Create(Runtime); Context1.Activate; TTestObject1.Project('TestObject'); Context1.RunScript(SScript, UnicodeString('TestProjectedClass1.js')); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context1.Global, 's1')), 's1'); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context1.Global, 's2')), 's2'); Context2.Activate; TTestObject1.Project('TestObject'); Context2.RunScript(SScript, UnicodeString('TestProjectedClass2.js')); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context2.Global, 's1')), 's1'); CheckEquals(UnicodeString('Hello'), JsStringToUnicodeString(JsGetProperty(Context2.Global, 's2')), 's2'); finally Context2.Free; Context1.Free; Runtime.Free; end; end; { TRectangle } type TRectangle = class(TNativeObject) class procedure InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); override; class function InitializePrototype(AConstructor: JsValueRef): JsValueRef; override; end; class procedure TRectangle.InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); var ArgsArray: PJsValueRefArray absolute Args; ShapeCtr: JsValueRef; begin if Self = TRectangle then begin // Shape.call(x, y); ShapeCtr := JsGetProperty(JsGlobal, 'Shape'); JsCallFunction(ShapeCtr, [ArgsArray^[0], ArgsArray^[1]], AInstance); // this.w = w; JsSetProperty(AInstance, UnicodeString('w'), ArgsArray^[2]); // this.h = h; JsSetProperty(AInstance, UnicodeString('h'), ArgsArray^[3]); end else inherited InitializeInstance(AInstance, Args, ArgCount); end; class function TRectangle.InitializePrototype(AConstructor: JsValueRef): JsValueRef; var ShapeCtr, ShapePrototype: JsValueRef; begin if Self = TRectangle then begin ShapeCtr := JsGetProperty(JsGlobal, 'Shape'); ShapePrototype := JsGetProperty(ShapeCtr, 'prototype'); // Rectangle.prototype = Object.create(Shape.prototype); Result := JsCreateObject(ShapePrototype); end else Result := inherited InitializePrototype(AConstructor); end; procedure TNativeClassTestCase.TestInheritance; // same tests as in TChakraCorePrototypes.TestInheritance, against ChakraCoreClasses.TNativeObject implementation // - Shape (x, y) => Object // - Circle (x, y, r) => Shape (x, y) // - Rectangle (x, y, w, h) => Shape (x, y) // - Square (x, y, w) => Rectangle (x, y, w, w) const SScript = // Shape: (Javascript) superclass 'function Shape(x, y) {' + sLineBreak + ' this.x = x;' + sLineBreak + ' this.y = y;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Shape.prototype.move = function(x, y) {' + sLineBreak + ' this.x += x;' + sLineBreak + ' this.y += y;' + sLineBreak + '};' + sLineBreak + sLineBreak + // Circle: (Javascript) subclass of (Javascript) Shape 'function Circle(x, y, r) {' + sLineBreak + ' Shape.call(this, x, y);' + sLineBreak + ' this.r = r;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Circle.prototype = Object.create(Shape.prototype);' + sLineBreak + 'Circle.prototype.constructor = Circle;' + sLineBreak + sLineBreak + // Square: (Javascript) subclass of (native) Rectangle 'function Square(x, y, w) {' + sLineBreak + ' Rectangle.call(this, x, y, w, w);' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Square.prototype = Object.create(Rectangle.prototype);' + sLineBreak + 'Square.prototype.constructor = Square;'; SName = 'TestInheritance.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; ShapeObj, CircleObj, RectangleObj, SquareObj: JsValueRef; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TRectangle.Project('Rectangle'); JsRunScript(SScript, SName); // var shapeObj = new Shape(10, 10); ShapeObj := JsNew('Shape', [IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, ShapeObj, 'shapeObj value type'); CheckTrue(JsInstanceOf(ShapeObj, 'Shape'), 'shapeObj instanceof Shape'); CheckFalse(JsInstanceOf(ShapeObj, 'Circle'), 'shapeObj instanceof Circle'); CheckFalse(JsInstanceOf(ShapeObj, 'Rectangle'), 'shapeObj instanceof Rectangle'); CheckFalse(JsInstanceOf(ShapeObj, 'Square'), 'shapeObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], ShapeObj); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y after move'); // var circleObj = new Circle(10, 10, 10); CircleObj := JsNew('Circle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, CircleObj, 'circleObj value type'); CheckTrue(JsInstanceOf(CircleObj, 'Shape'), 'circleObj instanceof Shape'); CheckTrue(JsInstanceOf(CircleObj, 'Circle'), 'circleObj instanceof Circle'); CheckFalse(JsInstanceOf(CircleObj, 'Rectangle'), 'circleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(CircleObj, 'Square'), 'circleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], CircleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y after move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r after move'); // var rectangleObj = new Rectangle(10, 10, 60, 40); RectangleObj := JsNew('Rectangle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(60), IntToJsNumber(40)]); CheckValueType(JsObject, RectangleObj, 'rectangleObj value type'); CheckTrue(JsInstanceOf(RectangleObj, 'Shape'), 'rectangleObj instanceof Shape'); CheckFalse(JsInstanceOf(RectangleObj, 'Circle'), 'rectangleObj instanceof Circle'); CheckTrue(JsInstanceOf(RectangleObj, 'Rectangle'), 'rectangleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(RectangleObj, 'Square'), 'rectangleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y before move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w before move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], RectangleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y after move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w after move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h after move'); // var squareObj = new Square(10, 10, 20); SquareObj := JsNew('Square', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(20)]); CheckValueType(JsObject, SquareObj, 'squareObj value type'); CheckTrue(JsInstanceOf(SquareObj, 'Shape'), 'squareObj instanceof Shape'); CheckFalse(JsInstanceOf(SquareObj, 'Circle'), 'squareObj instanceof Circle'); CheckTrue(JsInstanceOf(SquareObj, 'Rectangle'), 'squareObj instanceof Rectangle'); CheckTrue(JsInstanceOf(SquareObj, 'Square'), 'squareObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'sqaureObj.y before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], SquareObj); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'squareObj.y after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h after move'); finally Context.Free; Runtime.Free; end; end; type { TSquare } TSquare = class(TRectangle) class procedure InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); override; end; { TSquare } class procedure TSquare.InitializeInstance(AInstance: JsValueRef; Args: PJsValueRef; ArgCount: Word); var ArgsArray: PJsValueRefArray absolute Args; RectangleArgs: array[0..3] of JsValueRef; begin // Rectangle.call(this, x, y, w, w); RectangleArgs[0] := ArgsArray^[0]; RectangleArgs[1] := ArgsArray^[1]; RectangleArgs[2] := ArgsArray^[2]; RectangleArgs[3] := ArgsArray^[2]; inherited InitializeInstance(AInstance, @RectangleArgs[0], 4); end; procedure TNativeClassTestCase.TestInheritance2; const SScript = // Shape: (Javascript) superclass 'function Shape(x, y) {' + sLineBreak + ' this.x = x;' + sLineBreak + ' this.y = y;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Shape.prototype.move = function(x, y) {' + sLineBreak + ' this.x += x;' + sLineBreak + ' this.y += y;' + sLineBreak + '};' + sLineBreak + sLineBreak + // Circle: (Javascript) subclass of (Javascript) Shape 'function Circle(x, y, r) {' + sLineBreak + ' Shape.call(this, x, y);' + sLineBreak + ' this.r = r;' + sLineBreak + '}' + sLineBreak + sLineBreak + 'Circle.prototype = Object.create(Shape.prototype);' + sLineBreak + 'Circle.prototype.constructor = Circle;'; SName = 'TestInheritance2.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; ShapeObj, CircleObj, RectangleObj, SquareObj: JsValueRef; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TRectangle.Project('Rectangle'); TSquare.Project('Square'); JsRunScript(SScript, SName); // var shapeObj = new Shape(10, 10); ShapeObj := JsNew('Shape', [IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, ShapeObj, 'shapeObj value type'); CheckTrue(JsInstanceOf(ShapeObj, 'Shape'), 'shapeObj instanceof Shape'); CheckFalse(JsInstanceOf(ShapeObj, 'Circle'), 'shapeObj instanceof Circle'); CheckFalse(JsInstanceOf(ShapeObj, 'Rectangle'), 'shapeObj instanceof Rectangle'); CheckFalse(JsInstanceOf(ShapeObj, 'Square'), 'shapeObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], ShapeObj); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y after move'); // var circleObj = new Circle(10, 10, 10); CircleObj := JsNew('Circle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(10)]); CheckValueType(JsObject, CircleObj, 'circleObj value type'); CheckTrue(JsInstanceOf(CircleObj, 'Shape'), 'circleObj instanceof Shape'); CheckTrue(JsInstanceOf(CircleObj, 'Circle'), 'circleObj instanceof Circle'); CheckFalse(JsInstanceOf(CircleObj, 'Rectangle'), 'circleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(CircleObj, 'Square'), 'circleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], CircleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y after move'); CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'r')), 'circleObj.r after move'); // var rectangleObj = new Rectangle(10, 10, 60, 40); RectangleObj := JsNew('Rectangle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(60), IntToJsNumber(40)]); CheckValueType(JsObject, RectangleObj, 'rectangleObj value type'); CheckTrue(JsInstanceOf(RectangleObj, 'Shape'), 'rectangleObj instanceof Shape'); CheckFalse(JsInstanceOf(RectangleObj, 'Circle'), 'rectangleObj instanceof Circle'); CheckTrue(JsInstanceOf(RectangleObj, 'Rectangle'), 'rectangleObj instanceof Rectangle'); CheckFalse(JsInstanceOf(RectangleObj, 'Square'), 'rectangleObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y before move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w before move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], RectangleObj); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y after move'); CheckEquals(60, JsNumberToInt(JsGetProperty(RectangleObj, 'w')), 'rectangleObj.w after move'); CheckEquals(40, JsNumberToInt(JsGetProperty(RectangleObj, 'h')), 'rectangleObj.h after move'); // var squareObj = new Square(10, 10, 20); SquareObj := JsNew('Square', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(20)]); CheckValueType(JsObject, SquareObj, 'squareObj value type'); CheckTrue(JsInstanceOf(SquareObj, 'Shape'), 'squareObj instanceof Shape'); CheckFalse(JsInstanceOf(SquareObj, 'Circle'), 'squareObj instanceof Circle'); CheckTrue(JsInstanceOf(SquareObj, 'Rectangle'), 'squareObj instanceof Rectangle'); CheckTrue(JsInstanceOf(SquareObj, 'Square'), 'squareObj instanceof Square'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x before move'); CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'sqaureObj.y before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w before move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h before move'); JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], SquareObj); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'squareObj.y after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'w')), 'squareObj.w after move'); CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'h')), 'squareObj.h after move'); finally Context.Free; Runtime.Free; end; end; var CreatedCount: Integer = 0; DestroyedCount: Integer = 0; type TTestObject2 = class(TNativeObject) public constructor Create(Args: PJsValueRef = nil; ArgCount: Word = 0; AFinalize: Boolean = False); override; destructor Destroy; override; end; constructor TTestObject2.Create(Args: PJsValueRef; ArgCount: Word; AFinalize: Boolean); begin inherited Create(Args, ArgCount, AFinalize); Inc(CreatedCount); end; destructor TTestObject2.Destroy; begin Inc(DestroyedCount); inherited Destroy; end; function Get_Alive(Callee: JsValueRef; IsConstructCall: bool; Args: PJsValueRef; ArgCount: Word; CallbackState: Pointer): JsValueRef; {$ifdef WINDOWS}stdcall;{$else}cdecl;{$endif} begin Result := BooleanToJsBoolean(DestroyedCount = 0); end; // see that the finalizer gets called for a native instance if/when GC runs procedure TNativeClassTestCase.TestFinalizer; const SScript = // create native instance from script 'var obj = new TestObject2();' + sLineBreak + // release reference 'obj = null;' + sLineBreak + // wait for GC 'while (alive) {' + sLineBreak + // do some allocation to trigger GC eventually ' var obj = new Object();' + sLineBreak + '}'; SName = 'TestFinalizer.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TTestObject2.Project; JsDefineProperty('alive', False, False, JsCreateFunction(@Get_Alive, nil, UnicodeString('')), nil); CreatedCount := 0; DestroyedCount := 0; JsRunScript(SScript, SName); CheckEquals(1, CreatedCount, 'constructor calls'); CheckEquals(1, DestroyedCount, 'destructor calls'); finally Context.Free; Runtime.Free; end; end; // see that the finalizer gets called for a native instance if/when GC runs, or when the runtime is disposed procedure TNativeClassTestCase.TestFinalizer2; const SScript = 'var obj = new TestObject2();' + sLineBreak + 'obj = null;'; SName = 'TestFinalizer2.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TTestObject2.Project; CreatedCount := 0; DestroyedCount := 0; JsRunScript(SScript, SName); finally Context.Free; Runtime.Free; CheckEquals(1, CreatedCount, 'constructor calls'); CheckEquals(1, DestroyedCount, 'destructor calls'); end; end; // see that the finalizer gets called for a native instance if/when GC runs (invoked by host) procedure TNativeClassTestCase.TestFinalizer3; const SScript = 'var obj = new TestObject2();' + sLineBreak + 'obj = null;'; SName = 'TestFinalizer3.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create([ccroDisableBackgroundWork]); // doesn't seem to work with background GC Context := TChakraCoreContext.Create(Runtime); Context.Activate; TTestObject2.Project; CreatedCount := 0; DestroyedCount := 0; JsRunScript(SScript, SName); Runtime.CollectGarbage; CheckEquals(1, CreatedCount, 'constructor calls'); CheckEquals(1, DestroyedCount, 'destructor calls'); finally Context.Free; Runtime.Free; end; end; const FinalizerLoopCount = 10000; // see that repeated construction of a projected class no longer causes access violation // (constructors addrefed to prevent premature GC) procedure TNativeClassTestCase.TestFinalizer4; const SScript = 'var obj = new TestObject2();' + sLineBreak + 'obj = null;' + sLineBreak + ''; SName = 'TestFinalizer4.js'; var Runtime: TChakraCoreRuntime; Context: TChakraCoreContext; I: Integer; begin Runtime := nil; Context := nil; try Runtime := TChakraCoreRuntime.Create; Context := TChakraCoreContext.Create(Runtime); Context.Activate; TTestObject2.Project; CreatedCount := 0; DestroyedCount := 0; for I := 0 to FinalizerLoopCount - 1 do Context.RunScript(SScript, SName); finally Context.Free; Runtime.Free; CheckNotEquals(0, CreatedCount, 'constructor calls'); CheckEquals(CreatedCount, DestroyedCount, 'destructor calls'); end; end; initialization {$ifdef FPC} RegisterTests([TChakraCoreContextTestCase, TNativeClassTestCase]); {$else} RegisterTests([TChakraCoreContextTestCase.Suite, TNativeClassTestCase.Suite]); {$endif} end. ================================================ FILE: tests/tests.sh ================================================ #!/bin/bash function GetChakraCoreLibDir { CPU_TARGET=$1 OS_TARGET=$2 local __RESULT=$3 eval $__RESULT=$BASE_DIR/bin/chakracore/$CPU_TARGET-$OS_TARGET } function GetChakraCoreLibName { CPU_TARGET=$1 OS_TARGET=$2 local __RESULT=$3 if [ "$OS_TARGET" = "linux" ]; then eval $__RESULT=libChakraCore.so elif [ "$OS_TARGET" = "darwin" ]; then eval $__RESULT=libChakraCore.dylib elif [ "$OS_TARGET" = "win64" -o "$OS_TARGET" = "win32" ]; then eval $__RESULT=ChakraCore.dll fi } function GetLCL { CPU_TARGET=$1 OS_TARGET=$2 local __RESULT=$3 if [ "$OS_TARGET" = "linux" ]; then eval $__RESULT=gtk2 elif [ "$OS_TARGET" = "darwin" ]; then eval $__RESULT=cocoa elif [ "$OS_TARGET" = "win64" ]; then eval $__RESULT=win32 elif [ "$OS_TARGET" = "win32" ]; then eval $__RESULT=win32 fi } function Clean { CPU_TARGET=$1 OS_TARGET=$2 echo "Cleaning $CPU_TARGET-$OS_TARGET..." rm -r $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* rm -r $BASE_DIR/lib/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* } function Build { CPU_TARGET=$1 OS_TARGET=$2 CHAKRA_CORE_LIB_DIR= CHAKRA_CORE_LIB_NAME= GetChakraCoreLibDir $CPU_TARGET $OS_TARGET CHAKRA_CORE_LIB_DIR GetChakraCoreLibName $CPU_TARGET $OS_TARGET CHAKRA_CORE_LIB_NAME CHAKRA_CORE_LIB=$CHAKRA_CORE_LIB_DIR/$CHAKRA_CORE_LIB_NAME LCL= GetLCL $CPU_TARGET $OS_TARGET LCL FPC_OPTIONS="-n \ @$FPC_DIR/fpc.cfg \ -T$OS_TARGET \ -P$CPU_TARGET \ -MDelphiUnicode \ -Scghi \ -O1 \ -gl \ -l \ -vewnhibq \ -Fi$BASE_DIR/lib/$CPU_TARGET-$OS_TARGET/$BUILD_MODE \ -Fl$BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE \ -Fu$BASE_DIR/src \ -Fu$BASE_DIR/ext/jedi \ -Fu$FPCUP_DIR/lazarus/components/fpcunit/lib/$CPU_TARGET-$OS_TARGET/$LCL \ -Fu$FPCUP_DIR/lazarus/components/fpcunit \ -Fu$FPCUP_DIR/lazarus/components/synedit/units/$CPU_TARGET-$OS_TARGET/$LCL \ -Fu$FPCUP_DIR/lazarus/lcl/units/$CPU_TARGET-$OS_TARGET/$LCL \ -Fu$FPCUP_DIR/lazarus/lcl/units/$CPU_TARGET-$OS_TARGET \ -Fu$FPCUP_DIR/lazarus/components/lazutils/lib/$CPU_TARGET-$OS_TARGET \ -Fu$FPCUP_DIR/lazarus/packager/units/$CPU_TARGET-$OS_TARGET \ -Fu$BASE_DIR/. \ -FU$BASE_DIR/lib/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/ \ -FE$BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/ \ -dLCL \ -dLCL$LCL" if [ "$OS_TARGET" = "linux" ]; then FPC_OPTIONS+=" -Cg \ -k\"-L $CHAKRA_CORE_LIB_DIR\"" elif [ "$OS_TARGET" = "darwin" ]; then FPC_OPTIONS+=" -k\"-force_load $CHAKRA_CORE_LIB\"" elif [ "$OS_TARGET" = "win64" ]; then :; elif [ "$OS_TARGET" = "win32" ]; then :; fi mkdir -p $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE mkdir -p $BASE_DIR/lib/$CPU_TARGET-$OS_TARGET/$BUILD_MODE cp $CHAKRA_CORE_LIB $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE echo "Building $CPU_TARGET-$OS_TARGET..." FPC_CMD="$FPC_DIR/fpc $FPC_OPTIONS $BASE_DIR/tests/ChakraCoreTests.dpr" eval $FPC_CMD if [ $? != 0 ]; then exit $? fi FPC_CMD="$FPC_DIR/fpc $FPC_OPTIONS $BASE_DIR/tests/ChakraCoreTestsUI.dpr" eval $FPC_CMD if [ $? != 0 ]; then exit $? fi ls -lah $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE } # On Linux/OSX, libChakraCore.so/libChakraCore.dylib should be installed in a directory # which is included in the system library path (configured in etc/ld.so.conf), # e.g. /usr/local/lib or /usr/lib/x86_64-linux-gnu. # Otherwise set the LD_LIBRARY_PATH environment variable. function Test { CPU_TARGET=$1 OS_TARGET=$2 CHAKRA_CORE_LIB_DIR= CHAKRA_CORE_LIB_NAME= GetChakraCoreLibDir $CPU_TARGET $OS_TARGET CHAKRA_CORE_LIB_DIR GetChakraCoreLibName $CPU_TARGET $OS_TARGET CHAKRA_CORE_LIB_NAME CHAKRA_CORE_LIB=$CHAKRA_CORE_LIB_DIR/$CHAKRA_CORE_LIB_NAME TARGET_HOST= TARGET_USER=tondrej TARGET_DIR= if [ "$OS_TARGET" = "linux" ]; then # arrakis TARGET_HOST=arrakis.local TARGET_DIR=~/Test echo "Testing $CPU_TARGET-$OS_TARGET on $TARGET_HOST..." ssh $TARGET_USER@$TARGET_HOST "mkdir $TARGET_DIR/" ssh $TARGET_USER@$TARGET_HOST "rm -r $TARGET_DIR/*" scp -r $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* $TARGET_USER@$TARGET_HOST:$TARGET_DIR/ ssh $TARGET_USER@$TARGET_HOST "LD_LIBRARY_PATH=$TARGET_DIR/ $TARGET_DIR/ChakraCoreTests --all --progress --format=plain" >> test.log elif [ "$OS_TARGET" = "darwin" ]; then # kaitain TARGET_HOST=kaitain.local TARGET_DIR=/Users/tondrej/Test DYLD_DIR=/Users/tondrej/Development/ChakraCore/out/Release/bin/ChakraCore echo "Testing $CPU_TARGET-$OS_TARGET on $TARGET_HOST..." ssh $TARGET_USER@$TARGET_HOST "mkdir $TARGET_DIR/" ssh $TARGET_USER@$TARGET_HOST "rm -r $TARGET_DIR/*" scp -r $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* $TARGET_USER@$TARGET_HOST:$TARGET_DIR/ ssh $TARGET_USER@$TARGET_HOST "DYLD_LIBRARY_PATH=$DYLD_DIR $TARGET_DIR/ChakraCoreTests --all --progress --format=plain" >> test.log elif [ "$OS_TARGET" = "win64" ]; then # tleilax TARGET_HOST=tleilax.local TARGET_DIR=C:\\Users\\tondrej\\Test64 echo "Testing $CPU_TARGET-$OS_TARGET on $TARGET_HOST..." sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "mkdir $TARGET_DIR" sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "del /q /s $TARGET_DIR\\*.*" sshpass -p "$PASSWORD" scp -r $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* $TARGET_USER@$TARGET_HOST:$TARGET_DIR\\ sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "$TARGET_DIR\\ChakraCoreTests --all --progress --format=plain" >> test.log elif [ "$OS_TARGET" = "win32" ]; then # tleilax TARGET_HOST=tleilax.local TARGET_DIR=C:\\Users\\tondrej\\Test32 echo "Testing $CPU_TARGET-$OS_TARGET on $TARGET_HOST..." echo $PWD sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "mkdir $TARGET_DIR" sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "del /q /s $TARGET_DIR\\*.*" sshpass -p "$PASSWORD" scp -r $BASE_DIR/bin/$CPU_TARGET-$OS_TARGET/$BUILD_MODE/* $TARGET_USER@$TARGET_HOST:$TARGET_DIR\\ sshpass -p "$PASSWORD" ssh $TARGET_USER@$TARGET_HOST "$TARGET_DIR\\ChakraCoreTests --all --progress --format=plain" >> test.log fi } function Linux { Clean x86_64 linux Build x86_64 linux Test x86_64 linux } function Darwin { Clean x86_64 darwin Build x86_64 darwin Test x86_64 darwin } function Win64 { Clean x86_64 win64 Build x86_64 win64 Test x86_64 win64 } function Win32 { Clean i386 win32 Build i386 win32 Test i386 win32 } BUILD_MODE=Debug BASE_DIR=`dirname $0` BASE_DIR=$BASE_DIR/.. FPCUP_DIR=~/fpcupdeluxe FPC_DIR=$FPCUP_DIR/fpc/bin/x86_64-linux rm test.log Linux Darwin Win64 Win32 cat test.log