#51 Re: mORMot 1 » Display wrong characters even though data are intact after AES enc/dec » 2017-11-20 09:51:52

Many thanks for your help ! tongue
It works after the following change:

...
  {$IFDEF FPC}
  plain := mmoPlain.Text;
  {$ELSE ~FPC}
  plain := StringToUTF8(mmoPlain.Text);
  {$ENDIF ~FPC}
...
  {$IFDEF FPC}
  mmoPlain.Text := plain;
  {$ELSE ~FPC}
  mmoPlain.Text := UTF8ToString(plain);
  {$ENDIF ~FPC}
...

#52 Re: mORMot 1 » Why cannot deserialize TStrings prop if class inherits TPersistent ? » 2017-11-20 01:17:22

ab wrote:

IIRC there is an explicit check in SynCommons.pas which check for the TSynPersistent class type.

Many thanks for your helpful comments !
Indeed the explicit check for TSynPersistent class type is the root reason ! If SynCommons.TSynPersistent is found in the inheritance chain, the TSynPersistentClass(ItemClass).Create call ensures that the correct constructor is called. For TPersistent for example, the ItemClass.Create call goes to TObject.Create, in which case the deserialization will not work unless the field is initialized in the overridden AfterConstruction procedure.


procedure TClassInstance.Init(C: TClass);
begin
  ItemClass := C;
  if C<>nil then
  repeat // this unrolled loop is faster than cascaded if C.InheritsFrom()
    ...
    if C<>TSynPersistent then
    ...
      ItemCreate := cicTSynPersistent;
      exit;
    ...   
function TClassInstance.CreateNew: TObject;
begin
  ...
  case ItemCreate of
    ...
    cicTSynPersistent: begin
      result := TSynPersistentClass(ItemClass).Create;
      exit;
    end;
    ...
    cicTObject: begin
      result := ItemClass.Create;
      exit;
    end;
  ...
end;

#53 mORMot 1 » Why cannot deserialize TStrings prop if class inherits TPersistent ? » 2017-11-19 13:33:05

ComingNine
Replies: 2

I am trying to learn about the JSON deserialization inside mORMot. As shown in the code below (and in the compilable code in gist), I am trying to deserialize a class with a published TStrings property from JSON. The deserialization only works if the class inherits from SynCommons.TSynPersistent, and does not work if the class inherits from Classes.TPersistent. Interestingly, the deserialization also does not work if the TSynPersistent code is copied exactly into the .dpr and the class is made to inherit from this copy.

type
{$M+}

  // Exactly the same as in SynCommons.pas
  TSynPersistent = class(TObject)
  ...

//  TSample = class(TPersistent) // Does not work
  TSample = class(TSynPersistent) // Does not work
//  TSample = class(SynCommons.TSynPersistent) // Works
  private
    FContent: TStrings;
  published
    property Content: TStrings read FContent;
  public
//    constructor Create; // if inherits from TPersistent
    constructor Create; override; // if inherits from TSynPersistent or SynCommons.TSynPersistent
    destructor Destroy; override;

  end;
var
  Sample: TSample;
  JsonContentRaw: RawByteString;
  JsonContentUTF8: RawUTF8;
  JsonContentUTF8Buf: PUTF8Char;
  JsonContentValid: Boolean;
begin
    TJSONSerializer.RegisterClassForJSON([TSynPersistent, TSample]);

    Sample := TSample.Create;
    Sample.Content.Add('new line 3');
    SynCommons.FileFromString(ObjectToJSON(Sample, [woHumanReadable, woStoreClassName]), ChangeFileExt(ParamStr(0), '.Sample.json'));
    FreeAndNil(Sample);

    JsonContentRaw := SynCommons.StringFromFile(ChangeFileExt(ParamStr(0), '.Sample.json'));
    JsonContentUTF8 := CurrentAnsiConvert.AnsiToUTF8(JsonContentRaw);
    JsonContentUTF8Buf := @JsonContentUTF8[1];
    Sample := JSONToNewObject(JsonContentUTF8Buf, JsonContentValid) as TSample;
    Writeln(Format('%s', [BoolToStr(JsonContentValid, True)]));
    if JsonContentValid then
      Writeln(Format('%s', [Sample.Content.Text]));
end.

After following into mORMot.pas, it seems that the obvious reason could be that the GetterAddr(Instance) call returns the pointer to the underlying field if the class inherits from SynCommons.TSynPersistent, but returns a pointer to nil if the class inherits from TPersistent or, interestingly, the exact copy of TSynPersistent. Could you help to comment why a pointer to nil is returned if the class inherits from TPersistent or, more interestingly, the exact copy of TSynPersistent ? yikes

function TPropInfo.ClassFromJSON(Instance: TObject; From: PUTF8Char;
  var Valid: boolean; Options: TJSONToObjectOptions): PUTF8Char;
...  
  if GetterIsField then
    // no setter -> use direct in-memory access from getter (if available)
    Field := GetterAddr(Instance) else
    // no setter, nor direct field offset -> impossible to set the instance
    exit;
  result := JSONToObject(Field^,From,Valid,nil,Options);
...  

#54 Re: mORMot 1 » Display wrong characters even though data are intact after AES enc/dec » 2017-11-18 16:42:42

For Delphi, TMemo now shows correct characters after calls of CurrentAnsiConvert routines are modified to be "symmetric".  yikes

procedure TMainForm.btnEncryptWrongClick(Sender: TObject);
var
  Key: TSHA256Digest;
  plain, cipher: RawByteString;
begin
  SHA256Weak(CurrentAnsiConvert.UTF8ToAnsi(StringToUTF8(AES_KEY)), Key);
  plain := StringToUTF8(mmoPlain.Text);
  cipher := SynCrypto.AES(Key, 256, plain, true);
//  cipher := SynCrypto.AES(Key, 256, CurrentAnsiConvert.UTF8ToAnsi(plain), true);
  mmoCipher.Text :=  UTF8ToString(BinToBase64(cipher));
end;

procedure TMainForm.btnDecryptWrongClick(Sender: TObject);
var
  Key: TSHA256Digest;
  plain, cipher: RawByteString;
begin
  SHA256Weak(CurrentAnsiConvert.UTF8ToAnsi(StringToUTF8(AES_KEY)), Key);
  cipher := Base64ToBin(StringToUTF8(mmoCipher.Text));
  plain := SynCrypto.AES(Key, 256, cipher, false);
//  plain := CurrentAnsiConvert.AnsiToUTF8(SynCrypto.AES(Key, 256, cipher, false)); // Calling of CurrentAnsiConvert routines has to be "symmetric"
  mmoPlain.Text := UTF8ToString(plain);
end;

However, for FPC (on Windows), TMemo displays some characters correctly but question marks for others... O_O Could you help to comment about the reason of this behavior and possible workaround ?

The updated test files can be viewed at https://gist.github.com/anonymous/1995e … 1bad7f2974

#55 mORMot 1 » Display wrong characters even though data are intact after AES enc/dec » 2017-11-18 14:24:46

ComingNine
Replies: 3

I am trying to encrypt the content from the TMemo (Chinese characters), and then decrypt and show them. The data (bytes) seems to be the same after AES encryption/decryption, as can be seen by going to the address "plain[1]" in the Memory debug window. However, the TMemo cannot display the original/correct characters. Could you help to comment what is the correct way out here ? Many thanks ! O_O

PS: The situation is tested with Delphi 7 ( comment out type ChineseString = type Ansistring(936) ) and Delphi Tokyo.
PS: Under Delphi Tokyo, the line calling SHA256Weak generates complaint "W1058 Implicit string cast with potential data loss from 'string' to 'RawByteString'." I thought methods with RawByteString parameter are ready for any string argument... O_O Could you help to comment the correct way to call SHA256Weak ?

uses
  SynCommons, SynLog, SynCrypto;

const
  TEST_KEY: string = 'TEST_KEY';

procedure TMainForm.btnEncryptClick(Sender: TObject);
var
  Key: TSHA256Digest;
  plain, cipher: RawByteString;
begin
  SHA256Weak(TEST_KEY, Key);
  plain := StringToUTF8(mmoPlain.Text);
//  mmoPlain.Text := UTF8ToString(plain);
//  mmoPlain.Text := UTF8ToString(AnyAnsiToUTF8(plain));
//  Exit;
  cipher := SynCrypto.AES(Key, 256, plain, true);
  mmoCipher.Text :=  UTF8ToString(BinToBase64(cipher));
end;

type
  ChineseString = type Ansistring(936); // https://stackoverflow.com/questions/7222615/how-can-i-convert-string-encoded-with-windows-codepage-1251-to-a-unicode-string

procedure TMainForm.btnDecryptClick(Sender: TObject);
var
  Key: TSHA256Digest;
  plain, cipher: RawByteString;
  ChineseStr: ChineseString;
begin
  SHA256Weak(TEST_KEY, Key);
  cipher := Base64ToBin(StringToUTF8(mmoCipher.Text));
  plain := SynCrypto.AES(Key, 256, cipher, false);

  mmoPlain.Text := UTF8ToString(AnyAnsiToUTF8(plain)); // Does not work
//  mmoPlain.Text := UTF8ToString(CurrentAnsiConvert.AnsiToUTF8(plain)); // Does not work
//  mmoPlain.Text := UTF8ToUnicodeString(CurrentAnsiConvert.AnsiToUTF8(plain)); // Does not work

//  ChineseStr := UTF8ToString(AnyAnsiToUTF8(plain)); // Does not work
//  mmoPlain.Text := ChineseStr;

// mmoPlain.Text := TEncoding.Default.GetString(TBytes(@plain[1])); // Does not work
end;

The test files can be viewed at http://gist.github.com/anonymous/fa917e … 447137bcbb

#56 Re: mORMot 1 » Reset color to ccBlack instead of ccLightGray in TSynLog.ConsoleEcho ? » 2017-11-12 13:45:41

yikes Sorry. It seems that linking the Crt unit will drastically change how SynLog colorize the echoed log. For example, sllInfo level log will be bold instead of being ccWhite.

For me, it looks more natural to reset color to ccBlack instead of ccLightGray at the end of TSynLog.ConsoleEcho with Linux.

#57 Re: mORMot 1 » Reset color to ccBlack instead of ccLightGray in TSynLog.ConsoleEcho ? » 2017-11-12 13:10:02

It seems NormVideo is not void ?

Procedure NormVideo;
{
  Set normal back and foregroundcolors.
}
Begin
  TextColor(7);
  TextBackGround(0);
End; 

yikes I just tried to add "Crt.NormVideo" at the end of the above .lpr under FPC and it worked.

#58 Re: mORMot 1 » Reset color to ccBlack instead of ccLightGray in TSynLog.ConsoleEcho ? » 2017-11-12 11:10:43

Many thanks for your effort ! I will insert "Crt.NormVideo" at the end of .lpr under FPC smile

#59 Re: mORMot 1 » Reset color to ccBlack instead of ccLightGray in TSynLog.ConsoleEcho ? » 2017-11-11 11:15:34

After searching the internet I am still not sure. For example, on some distributions the default terminal color is dependent on the "theme". Perhaps it is better to leave it as is...

#60 mORMot 1 » Reset color to ccBlack instead of ccLightGray in TSynLog.ConsoleEcho ? » 2017-11-10 16:45:25

ComingNine
Replies: 7

Since normally the console color is black, could you consider to reset color to ccBlack instead of ccLightGray at the end of TSynLog.ConsoleEcho ?
Currently, if EchoToConsole is set to LOG_VERBOSE, the color of the prompt for the next command becomes from black to light gray, which seems odd... big_smile

Example:

program Project1;

{$IFNDEF FPC}
{$APP CONSOLE}
{$ENDIF}

uses
  SysUtils,
  SynCommons, SynLog;

procedure xx;
var
 ILog: ISynLog;
 SMethodName: string;
 SMethodNameUTF8: RawUTF8;
begin
  SMethodName := 'enter xx';
  SMethodNameUTF8 := StringToUTF8(SMethodName);
  (*
    [url]https://synopse.info/forum/viewtopic.php?pid=25540[/url]
    @ returns a pointer to a variable: @str is a pointer to the string pointer, not to the string content
    @str[1] is a pointer to the first char, i.e., the pointer to the string content
    Pointer() type-cast the variable to another type: hard-cast of a string variable as Pointer returns the pointer to the string content
  *)
  // Does not work.
  // ILog := TSynLog.Enter(nil, @SMethodNameUTF8);
  // Either way works.
  ILog := TSynLog.Enter(nil, @SMethodNameUTF8[1]);
  // ILog := TSynLog.Enter(nil, Pointer(SMethodNameUTF8));
  ILog.Log(sllWarning, 'hi xx');
end;

begin
  with TSynLog.Family do
  begin
    {$IFDEF MSWINDOWS}
      AutoFlushTimeOut := 1;
    {$ENDIF ~MSWINDOWS}
    Level := LOG_VERBOSE;
    EchoToConsole := LOG_VERBOSE;
    PerThreadLog := ptIdentifiedInOnFile;
    RotateFileCount := 50;
    RotateFileSizeKB := 20 * 1024; // rotate by 20 MB logs
  end;

  xx;
end.

rh4c5i.png

#62 Re: mORMot 1 » How to use the version of TSynLog.Enter with PUTF8Char parameter ? » 2017-11-10 14:01:00

Thank you very much for your helpful explanation !

@SMethodNameUTF8 is in fact what I have used, and does not work as shown.

However, Pointer(SMethodNmeUTF8) does work. The overloaded TSynLog.Enter method, which uses TextFmt/TextArgs input parameters, is even better.

Could you help to comment why Pointer(SMethodNmeUTF8) works but @SMethodNameUTF8 does not ? yikes
Is it documented that hard-cast of a string variable as Pointer returns the pointer to the string content ? yikes

#63 mORMot 1 » How to use the version of TSynLog.Enter with PUTF8Char parameter ? » 2017-11-10 10:26:22

ComingNine
Replies: 4

I try to provide customized string to TSynLog.Enter. However, the following code gives unreadable characters as shown in the picture. The same problem can be seen with Delphi/Win, FPC/Win and FPC/Linux.

Could you help to show the correct way to use the version of TSynLog.Enter with PUTF8Char parameter ? big_smile Many thanks !

program Project1;

{$IFNDEF FPC}
{$APPTYPE CONSOLE}
{$ENDIF}

uses
  SysUtils,
  SynCommons, SynLog;

procedure xx;
var
 ILog: ISynLog;
 SMethodName: string;
 SMethodNameUTF8: RawUTF8;
begin
  SMethodName := 'enter xx';
  SMethodNameUTF8 := StringToUTF8(SMethodName);
  ILog := TSynLog.Enter(nil, @SMethodNameUTF8);  // <--- Will show unreadable character
  ILog.Log(sllWarning, 'hi xx');
end;

procedure yy;
var
 ILog: ISynLog;
 SMethodName: string;
 SMethodNameUTF8: RawUTF8;
begin
  SMethodName := 'enter yy';
  SMethodNameUTF8 := StringToUTF8(SMethodName);
  ILog := TSynLog.Enter(nil, @SMethodNameUTF8);  // <--- Will show unreadable character
  ILog.Log(sllWarning, 'hi yy');
end;

begin
  with TSynLog.Family do
  begin
    {$IFDEF MSWINDOWS}
      AutoFlushTimeOut := 1;
    {$ENDIF ~MSWINDOWS}
    Level := LOG_VERBOSE;
    EchoToConsole := LOG_VERBOSE;
    PerThreadLog := ptIdentifiedInOnFile;
    RotateFileCount := 50;
    RotateFileSizeKB := 20 * 1024; // rotate by 20 MB logs
  end;

  xx;
  yy;
end.

30auyo3.png

#64 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-08-20 08:51:40

Dear mpv, could you share us the news of SyNode support with NewPascal under Linux smile

#65 Re: mORMot 1 » Certain property makes the generated json invalid to parse back. » 2016-12-20 08:47:49

Many thanks !

> IMHO it is up to the consumers (other objets) to make their own private copy of the original dynamic array.
In principle you are right.

Still, it does not hurt anyone to be defensive, when the overhead of copying the primitive array is negligible. big_smile

> Using such a getter is slower when you access the array items,

Iteration will not be done on the property but always on a local var instead. "ArrByRef" is provided in case "consumer" is reading only.

> , and also probably misleading the serializer expectations.

Apparently the serializer is "definitely" misled. The value of "Arr" is "[]", which should be the same as the value of "ArrByRef" "[0]" or "[0,1,..]". Therefore, could you help to comment whether it is technically possible for mORMot to serialize "Arr" property correctly here ? big_smile

#66 Re: mORMot 1 » Certain property makes the generated json invalid to parse back. » 2016-12-19 14:46:13

mpv wrote:

In your code:

function TPOJO.GetArr: TIntegerDynArray;
begin
  Result := Copy(FArr);
end;

Are you sure what doing a copy of an array inside the property getter is a good idea? Why do so?

Providing a copy of a primitive array serves me very well when the original primitive array is held by a object ("manual-Box" since there is no auto-Box) and needed by other objects who go on to modify the array according to their own needs.

#67 mORMot 1 » Certain property makes the generated json invalid to parse back. » 2016-12-19 13:30:49

ComingNine
Replies: 4

Dear ab, in the sample code below which tries to serialize a plain object and then de-serialize, it seems that certain property ("Arr" as in the sample) makes the generated json invalid (see the value of "Arr", which should be the same as the value of "ArrByRef") to parse back (see the difference of "ArrByRef" in the above and below block, which should be the same. Apparently, JsonToObject detects invalid json content and aborts parsing). If that "Arr" property is removed from the published section, the generated json is valid and can be parsed back. Could you help to comment whether this is a bug or by design ? yikes Many thanks !

https://gist.github.com/anonymous/333f077797aecdc0ee65253e8ad819ba

#68 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-11-08 07:39:04

ComingNine wrote:

Dear mpv, I am trying to access the "mainForm" exported by the host SpiderMonkey45Binding.exe from the plugin mathModule.dll. The reason behind my attempt is that if this is indeed possible, this looks like a good way of manipulating "central business service" exported by the host .exe from plugin .dll. Complex additional manipulation referencing the "central business service" could be compiled into plugin .dll without changing the host .exe.......

http://www.delphigroups.info/2/f9/304620.html
http://www.delphigroups.info/2/41/523159.html
http://www.delphigroups.info/2/aa/523141.html

According to the links above, the prerequisite is that (1) everything which needs to be referred to in both .exe and .dll should be put into a package, and (2) both .exe and .dll should be built with Runtime-package enabled.

Furethermore, according to the FastMM FAQ, these FullDebugMode, UseRuntimePackages, ShareMM, ShareMMIfLibrary, AttemptToUseSharedMM defines are enabled. Also, according to one post on the FastMM forum, FastMM is put into its own package and referred to in all other packages, .exe, and .dll projects.

However, the problem now is that when testing in Win7 x64 VM (1 core, 2GB mem), memory leaks are reported when main form is shut down, which should be related to the unload order of runtime packages. sad
Note that there are no memory leaks reported in Win10 x61 OS (4 core, 32GB mem).

The modified files are upload as mORMot.20161108151029.zip, and the steps to reproduce the memory leaks are below:

(*

In Win7 x64 VM (1 core, 2GB mem),
use D:\mORMot\SyNode\Samples\02 - Bindings\SpiderMonkey45Binding_D24.bat to run the main form,
paste the javascript below, 
run any of them, 
close main form directly without closing Form1 or Form2, 
there is memory leak:

const mathModule = require('../../Samples/01 - Dll Modules/math-module');
mathModule.work_tform1_1(mainForm)
mathModule.work_tform1_2(mainForm)
mathModule.work_tform1_3(mainForm)
mathModule.work_tform2_1(mainForm)
mathModule.work_tform2_2(mainForm)
mathModule.work_tform2_3(mainForm)

--------------------------------2016/11/8 15:04:04--------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):

13 - 20 bytes: AnsiString x 2
21 - 36 bytes: AnsiString x 1, Unknown x 2
37 - 52 bytes: TSMDebugger x 1
69 - 84 bytes: TCrtSocket x 1
85 - 100 bytes: TSMRemoteDebuggerThread x 1
149 - 164 bytes: TObjectListLocked x 2
245 - 276 bytes: TRawUTF8ListHashedLocked x 2

*)

ShareMem in the uses clause and replacement BorlndMM.dll in the path does not help.
FastMM's NeverUninstall combined with disabling FastMM's reporting memory leaks completely makes debugging memory leaks much more difficult.

Could you help to comment whether it is possible to prevent the memory leaks when using runtime packages, by making FastMM to unload last or in some other ways ? big_smile

#69 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-11-05 12:42:45

Dear mpv, I am trying to access the "mainForm" exported by the host SpiderMonkey45Binding.exe from the plugin mathModule.dll. The reason behind my attempt is that if this is indeed possible, this looks like a good way of manipulating "central business service" exported by the host .exe from plugin .dll. Complex additional manipulation referencing the "central business service" could be compiled into plugin .dll without changing the host .exe.

Modified files are uploaded onto gist : uMathModule.pas belongs to "01 - Dll Modules\math-module\src\" and the rest six files belong to "02 - Bindings".

However, I have met several problems in trying with the above files:

(1) The plugin methods have to reference the business class. That is to say, ufrmSM45Demo has to be used in uMathModule.pas. But then the type incompatibility issue arises. For example, in function try_work_tform1_1, InstRec.instance is TfrmSM45Demo fails. I wonder whether it is safe or dangerous to hard cast as done in the code ?

(2) Further attempts try to access the ability of the mainForm , which is obtained by hard-cast, to evaluate JavaScript. In other words:
  (a) host evaluates JavaScript string, where host exports mainForm
  (b) in the JavaScript string, host calls plugin JS method with the mainForm exported
  (c) in the plugin native method, the mainForm obtained by hard-cast is asked to evaluate JavaScript

  However, the attempts all fail: function try_work_tform1_2 does not completes 100% correct, and function try_work_tform2_2 gives access violation; function try_work_tform1_3 and try_work_tform2_3 both give "A component named Form? already exists."

(3) The above problems are the same no matter FastMM4 or ShareMem is used for host or plugin or both.

Could you help to check the code and comment the reason ?  big_smile

Furthermore, if I am taking the wrong way, could you help to comment the correct solution to access the "central business service" of host .exe within the plugin dll ? big_smile

#70 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-11-05 08:23:30

mpv wrote:

About rooting in SpiderMonkey:

Everything (strings, objects, integers, result of CreateJSInstanceObjForSimpleRTTI call, etc.) inside SpiderMonkey represented as JSValue - a 64 bit structure. SpiderMonkey engine create a reference counter for each structure, and when reference counter === 0 will free a JSValue (during garbage collection circle) - this is the same as for Strings or dynamic array in Delphi, but in Delphi string will be destroyed just after reference counted became zero, in JavaScript - when garbage collection circle is executed.

 
jsval := CreateJSInstanceObjForSimpleRTTI(....); // 0) create a new JSValue inside Engine
try
  rootObj := cx.NewRooted*(jsval); // 1) When we want to use a JSValue from outside the SpiderMonkey Engine (from Delphi code) we must say Engine to increase a reference counter
  // do something with JSValue
  vp.rval := rootObj.ptr.ToJSValue; //see notes* below about ptr
finally 
  cx.FreeRooted*(rootObj); // 2) When we do not need a reference to JSValue from Delphy, we must say Engine to decrease a reference counter by

cx.FreeRooted is not actually a Free operation - just a dec to the internal reference counter.

Notes* about ptr
Between events 1) and 2) SpiderMonkey can in any moment run a internal memory optimization procedure and move the actual in-memory position of the JSValue to another place. This is why we must not memorize a direct pointer to a JSValue (in our case jsval created on the step 0), but use a rootObj.ptr.

Notes about root/unroot order
Important thing about rooting/unrooting order - inside the SM45 rooting is a stack, so we must unroot things in order opposite we root it. In C++ this solved by automatically variable scoping. In Delphi even if we use a Variants as AB did in SM24 there is no guaranty of variant uninit order, so we must manually and carefully root/unroot.

I appreciate your efforts and helpful comments very much !

ab wrote:

AFAIR the Delphi Web Script JavaScript back-end has been released again under Open Source.
We may include it to compile directly from high-level pascal to JavaScript, then execute it in SyNode... and its full JIT performance... may be a perspective of some interest...

Sounds really interesting ! Looking forward to the proto type big_smile

#71 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-31 10:33:22

Dear Orel,

  thank you very much for your kind help and instructive sample code ! cool

  PS: It seems that in your above post and also your #26 post, one should pay strict attention to the rooting and the exception handling.

  Could you help to comment whether you would suggest that I revise the code below (also shown in my #35 post) accordingly ? Many thanks !

  From

function TfrmSM45Demo.NewForm1(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
var
  Frm1: TForm1;
begin
  Frm1 := TForm1.Create(Self);
  vp.rval := CreateJSInstanceObjForSimpleRTTI({FEngine.}cx, Frm1, FEngine.GlobalObject);
  Result := True;
end;

  to

function TfrmSM45Demo.NewForm1(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
var
  frm1: TForm1;
  rootObj: PJSRootedObject;
begin
  try
    frm1 := TForm1.Create(Self);
    try
      rootObj := cx.NewRootedObject(CreateJSInstanceObjForSimpleRTTI({FEngine.}cx, frm1, FEngine.GlobalObject));
      vp.rval := rootObj.ptr.ToJSValue;
    finally
      cx.FreeRootedObject(rootObj);
    end;
    Result := True;

  except
    on E: Exception do
    begin
      Result := False;
      vp.rval := JSVAL_VOID;
      JSError(cx, E);
    end;
  end;

More over, if the above revision is correct, could you help to comment why there is cx.FreeRootedObject(rootObj); ? I mean, the return value of this JSNative function, vp.rval, will be needed afterwards. The vp.rval stores rootObj.ptr.ToJSValue, but rootObj is freed ? The GC Rooting Guide does not help me understand here. It really puzzles me yikes

#72 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-31 08:49:13

mpv wrote:

About fs.writeFile* - we are working on `fs` module right now (this part is already implemented inside UnityBase, but we need do remove some internal dependencies to move it to SyNode)

About `lodash` - you can use it right now
1) Install lodash

>cd "D:\Work\synopse\SyNode\Samples\02 - Bindings\" 
>npm install lodash

2) Use it

var _ = require('lodash');
var sortedSQ = _([3, 2, 1]).map( (x) => x*x ).sort().values();
mainForm.toLog(JSON.stringify(sortedSQ));

Dear mpv and Orel,

at the #26, #29 posts of this thread, Orel has mentioned that Delphi array and JS (normal/typed ?) array are different things. Could you help to suggest how to code the JSNative function at Delphi side, to return array to JS side, which can be used with lodash ? Many thanks !

#73 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-29 11:33:06

mpv wrote:

We commit a huge improvement to the SyNode. The most important changes are:
- x64 SpiderMonkey support - compiled x64 binary is here. Tested with XE2 & XE4
- nodeJS Buffer binding & Buffer module
- pure JavaScript implementation of timer loop, so setTimeout/setInterval etc. are now work as expected

@ComingNine - also this commit fix a issue with JS_GetSharedArrayBufferViewType.

Since we now have a Buffer we can implement a fully nodeJS compatible fs module. Current implementation is based on AnyTextFileToRawUTF8 and do not allow chunked file reading/writing

Really great news ! Really fabulous work !! cool

#74 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-28 16:34:00

Dear mpv, could you help to comment the following problem of mine ? Many thanks !

I had a Delphi .dpk package (for Win32) which could build and install without any problem. However, after adding JavaScript-related code (thanks to great mORMot and SyNode projects), even if the mozjs-45.dll, nsp4.dll and the rest dll files are within the .bpl directory, or put into C:\Windows\SysWOW64, the package can no longer be installed. The error is

The procedure entry point JS_GetSharedArrayBufferViewType could not be located in the dynamic library test.bpl 

It is really confusing me because mozjs-45.dll is right there in the same directory as the .bpl file. yikes

Could you help to comment about the reason and possibly the workround ? Many thanks !

#75 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-27 15:07:08

mpv wrote:

About fs.writeFile* - we are working on `fs` module right now (this part is already implemented inside UnityBase, but we need do remove some internal dependencies to move it to SyNode)

About `lodash` - you can use it right now
1) Install lodash

>cd "D:\Work\synopse\SyNode\Samples\02 - Bindings\" 
>npm install lodash

2) Use it

var _ = require('lodash');
var sortedSQ = _([3, 2, 1]).map( (x) => x*x ).sort().values();
mainForm.toLog(JSON.stringify(sortedSQ));

Great to know that !

Thank you for your efforts and helpful comments ! smile

#76 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-27 13:41:13

mpv wrote:

You can get a pointer to the native (Delphi) instance using IsInstanceObject. Unfortunately, we lost a variant compatibility for a complex types because of rooting mechanism in SM45

var
  res: jsval;
  instRef: PSMInstanceRecord;
..
res := FEngine.CallObjectFunction(FEngine.GlobalObject, 'NewForm1AsJSFunc', []);
if IsInstanceObject(FEngine.cx, res, instRef) then
  if (instRef.instance is TForm) then
    .. do something with TForm

Thank you very much for your instructions !

mpv wrote:
ComingNine wrote:

Please notice that the first letter of the published property has to be typed in lower case, and there is no such restriction regarding the first letter of the published function.
Could you help to comment about the reason ? Is it possible to remove the restriction for published properties ?

I'm force the conversion of first character of Delphi properties to the lower case to follow JavaScript naming convention. We do not do it for a method's, because method's (function in term of JS) can be a constructor  (as you write in example above mainForm.NewForm1() ), and JavaScript naming convention for constructors is "start it name from a upper case". So this is a developer responsibility to name the methods in a right way (camelCase for usual functions, StartFromUpper for a functions what must be called with new).

Thank you very much for your helpful comments !

PS: Could you also help to comment about my problems concerning undefined JS functions in #34 post of this thread ? More importantly, do you recommend loading into SyNode renowned JS libraries such as Node.js and Lodash and so forth ? I mean, on the official page of Node.js, it is written that Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine...

smile Many thanks !

#77 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-26 15:04:43

Dear mpv,

Could you help to comment about returning Delphi object from JavaScript function, using mORMot\SyNode\Samples\02 - Bindings as an example:
(1) add TForm1 to the project, as shown in #35 post of this thread, and modify the btnEvaluateClick as below

procedure TfrmSM45Demo.btnEvaluateClick(Sender: TObject);
var
  res: jsval;
  Frm1V: Variant;
  Frm1: TForm1;
begin
  // evaluate a text from mSource memo
  if mSource.SelText <> '' then
    FEngine.Evaluate(mSource.SelText, 'mSourceSelected.js', 1, res)
  else
    FEngine.Evaluate(mSource.lines.Text, 'mSource.js', 1, res);

  res := FEngine.CallObjectFunction(FEngine.GlobalObject, 'NewForm1AsJSFunc', []);
  Frm1V := res.asSimpleVariant[FEngine.cx];  <---- ESMException in function jsval.getSimpleVariant(cx: PJSContext): Variant;
  Frm1 := TVarData(V).VPointer; // Seems feasible to hold object in Variant according to Barry Kelly's comment in this SO post http://stackoverflow.com/questions/366329/why-cant-delphi-variants-hold-objects
  Frm1.Caption := 'hello ! Delphi Object from JavaScript!';
end;

(2) when running, in the left memo, type in the following code and evaluate. Unfortunately, ESMException occurs in function jsval.getSimpleVariant(cx: PJSContext): Variant;

function NewForm1AsJSFunc()
{
    var f = mainForm.NewForm1()
    return f
}

Could you help to finish the TODOs concerning JSTYPE_OBJECT and JSTYPE_FUNCTION in function jsval.getSimpleVariant, so that Delphi code can call JavaScript functions which return customized Delphi object ?

#78 Re: Free Pascal Compiler » mORMot and FPC 3.0/3.1.1 » 2016-10-26 07:41:47

Many thanks for your helpful comments ! big_smile

#79 Re: Free Pascal Compiler » mORMot and FPC 3.0/3.1.1 » 2016-10-25 10:56:12

AOG wrote:

Latest mORMot for FPC here: https://github.com/newpascal-ccr/mORMot/

Dear AOG, does this mean that we can download zipped archive from that github link and replace the c:\NewPascal\ccr\mORMot ?

If yes, can you comment whether you can keep mORMot in your github link above always sync with http://synopse.info/fossil/timeline ?

Many thanks !

#80 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-23 15:09:09

Taking "mORMot\SyNode\Samples\02 - Bindings" for example, if another TForm descendant unit is added

unit Unit1;

interface

uses
  SysUtils, Classes, Forms;

type
{$M+}

  TWorker = class
  private
    fName: string;
  public
    constructor Create;
  published
    property Name: string read fName;
  end;

  TForm1 = class(TForm)
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    fWorker: TWorker;
  public
  published
    property Worker: TWorker read fWorker;
  end;

implementation

{ TWorker }

constructor TWorker.Create;
begin
  fName := 'A new TWorker instance';
end;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  fWorker := TWorker.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  fWorker.Free;
end;

end.

,and the ufrmSM45Demo unit is modified with the addition of

...
published
...
    function NewForm1(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
...
function TfrmSM45Demo.NewForm1(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
var
  Frm1: TForm1;
begin
  Frm1 := TForm1.Create(Self);
  vp.rval := CreateJSInstanceObjForSimpleRTTI({FEngine.}cx, Frm1, FEngine.GlobalObject);
  Result := True;
end;

,one can run the JavaScript code below

var f = mainForm.NewForm1()
mainForm.toLog(f.worker.name)

.

Please notice that the first letter of the published property has to be typed in lower case, and there is no such restriction regarding the first letter of the published function.
Could you help to comment about the reason ? Is it possible to remove the restriction for published properties ? big_smile

#81 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-22 14:15:48

Could you help to comment a few more small problems that I meet when trying mORMot\SyNode\Samples\02 - Bindings:

(1) when running, in the left memo, calling fs.writeFileSync fails complaining writeFileNew is undefined, calling fs.appendFileSync fails complaining appendFileNew is undefined.

(2) when running, in the left memo, calling alert fails complaining alert is undefined...

(3) when running, in the left memo, calling const console = require('console') or const console = require('console').Console fails complaining Console expects a writable stream instance...

(4) when running, in the left memo, adding four lines below will not trigger function TStringsTextRead at all(breakpoint does not stop)... Is TStringsProto used at all in this sample ?

let msg1 = mainForm.results.Text
let msg2 = mainForm.results

var msg3 = mainForm.results.Text
var msg4 = mainForm.results

(5) when running, in the left memo, var x = new TStrings() is evaluated without error, even after the aEngine.defineClass(mSource.lines.ClassType, TStringsXProto, aEngine.GlobalObject); line in the source code is commented out. Why is this possible ? It seems that SyNode does not automatically call defineClass by itself.

(6) when running, in the left memo, after the code below is evaluated, the right memo gives "HelloWorld" without the line break ? More importantly,  neither function TStringsTextRead nor function TStringsWrite is triggered (breakpoint does not stop)...

var x = new TStrings()
x.Text = "Hello\nWorld"
mainForm.toLog(x.Text)

var y = new TMemoStrings()
y.Text = "Hello\nWorld"
mainForm.toLog(y.Text)

[7] when running, in the left memo, the code below exemplifies the usage of TStringsProto to me ! big_smile

mainForm.toLog("line 1");
mainForm.toLog("line 2\r\nline 3");
mainForm.toLog("line 4");

let l_memo = mainForm.results /* results is the published property of TMainForm and thus accessible automatically ? */
let l_memostrings = mainForm.results.lines /* Lines is the published property of TMemos and thus accessible automatically, as implemented in SyNodeSimpleProto.pas:477: ? */
var v_memo = mainForm.results /* Points to the same reference as l_memo */
var v_memostrings = mainForm.results.lines /* Points to the same reference as l_memostrings */

/* TStringsTextRead */
mainForm.toLog("l_memo.lines.text: " + l_memo.lines.text) 
mainForm.toLog("v_memo.lines.text: " + v_memo.lines.text) 

/* TStringsTextWrite */
l_memostrings.text = "line 1\r\nline 2\r\nline 3\r\nline 4"
mainForm.toLog("v_memostrings.text: " + v_memostrings.text) 

Many thanks !! yikes big_smile

#82 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-22 11:57:20

mpv wrote:

You should expose classes TWorkerForm & TWorker to the engine using TSMEngine.defineClass method. In JavaScript you must define a prototype for a class - for Delphi objects you have 2 choice TSMSimpleRTTIProtoObject & TSMNewRTTIProtoObject.

In the sample "02 - Bindings" we define a prototype TStringsProto and register it in the DoOnCreateNewEngine - see the sample sources . After a class is registered you can create it directly from JS using

var myForm = new TWorkerForm()

Thank you very much for your instructions !
Nonetheless, even though TSringsProto is defined in the sample "02 - Bindings", there seems to be lack of any exemplary usage of it… Could you suggest me the guideline to implement feature like var viewFrm = mainForm.ViewForms.Add ? I mean, after I use defineClass, how should I implement correctly the typed collection properties (ViewForms) of mainForm, and the Add method of the typed collection ? Many thanks !

#83 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-22 03:17:40

Dear mpv and Orel,

Could you help to comment how to use SyNode (SpiderMonkey) to expose a whole set of Delphi class/object hierarchy to JavaScript ?

As shown in ADOBE ILLUSTRATOR CC 2015.3 SCRIPTING REFERENCE: JAVASCRIPT, Adobe Illustrator has exposed its whole CPP class/object hierarchy to JavaScript. Consequently, we can create arbitrary Illustrator CPP instances within JavaScript, and call methods of these Illustrator CPP instances within JavaScript.

#include "lib/lodash.3.10.1.js"
    var docRef = Application.Documents.Add();  // Create an empty Document with default settings
    ...
    var groupRef = docRef.layers[0].groupItems[0];  // Manipulate the properties of the newly-created Document
    _.each(groupRef.pathItems, function(pathItemRef)
    {
      if(pathItemRef.strokeDashes.length >= 1)
      {
        pathItemRef.strokeWidth = 2.0;
        pathItemRef.strokeDashes = [2, 4];
      }     
    })

Nonetheless, as shown in the DoOnCreateNewEngine callback in mORMot\SyNode\Samples\02 - Bindings, it seems that only existing Delphi instance is exposed to the JavaScript global object as property.

 
  aEngine.GlobalObject.ptr.DefineProperty(aEngine.cx, 'mainForm',
    // proeprty value is a wrapper around the Self
    CreateJSInstanceObjForSimpleRTTI(aEngine.cx, Self, aEngine.GlobalObject),
    // we can enumerate this property, it read-only and can not be deleted
    JSPROP_ENUMERATE or JSPROP_READONLY or JSPROP_PERMANENT
  );

Furthermore, as shown in 22.3.2. Calling Delphi code from JavaScript, it seems that only method of existing Delphi instance is exposed to the JavaScript global object as method.

procedure TTestServer.DoOnNewEngine(const Engine: TSMEngine);
...
  // add native function to the engine
  Engine.RegisterMethod(Engine.GlobalObj,'loadFile',LoadFile,1);
end;
function TTestServer.LoadFile(const This: variant; const Args: array of variant): variant;
begin
  if length(Args)<>1 then
    raise Exception.Create('Invalid number of args for loadFile(): required 1 (file path)');
  result := AnyTextFileToSynUnicode(Args[0]);
end;

Lastly, I could not figure out how to do this from https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Cookbook

I am therefore rather lost how to achieve similar effect with SyNode (SpiderMonkey). For the hierarchy shown below, could you help to comment how to expose not only the instance of the TMainForm class but also the TWorkerForm and TWorker classes (instances may not be created yet), so that TWorderForm can be created  in JavaScript, and methods of TWorker can be called in JavaScript ?
RrgQHb3.png

Many thanks !!

#85 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-19 09:14:12

Dear Orel, thank you very much for your knowledgeable posts ! (PJSRootedObject does not have isObject so that mResult.Lines.Add(BoolToStr(jsArr.isObject, True)); line has to be commented out.)
It then seems that we could not get Delphi array directly from jsval but has to call ptr.GetElement(cx, index, jsArrElement); manually.

#86 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-19 02:32:52

Could you help to comment why the "jsval.asDouble" returns NaN for 0.0 and 1.0 and so forth in the code below, and how to work around this inconvenience ? Is it not possible to pass 0.0 to JavaScript function and retrieve afterwards ? Many thanks !
PS: The function can be appended to SpiderMonkey45Binding: ufrmSM45Demo.

// mainForm.JSTestOnlyZeroAfterDecimal(0.0)    <--- NaN
// mainForm.JSTestOnlyZeroAfterDecimal(0.010)
// mainForm.JSTestOnlyZeroAfterDecimal(1.0)    <--- NaN
// mainForm.JSTestOnlyZeroAfterDecimal(1.010)
function TfrmSM45Demo.JSTestOnlyZeroAfterDecimal(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
var
  dblval: Double;
begin
  dblval := vp.argv[0].asDouble;
  mResult.Lines.Add('########    ' + FloatToStrF(dblval, ffFixed, 20, 8) + '   ########');
  Result := True;
end;

#87 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-18 16:06:48

Could you help to comment why the "JSObject.Is***Array" returns false in the code below ? The array element is apparently numeric. Many thanks !

PS: The function can be appended to SpiderMonkey45Binding: ufrmSM45Demo.

// Test with: 
//   mainForm.JSTestArray1D([1,2,3])
//   mainForm.JSTestArray1D([1.0,2.0,3.0])
//   mainForm.JSTestArray1D([1.1,2.2,3.3])  
function TfrmSM45Demo.JSTestArray1D(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean;
var
  jsArr, jsArrElement: jsval;
  Cnt, I: Cardinal;
begin
  jsArr := vp.argv[0];
  mResult.Lines.Add('###########################');
  mResult.Lines.Add(BoolToStr(jsArr.isObject, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.isArray(cx), True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsTypedArrayObject, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsInt8Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsUInt8Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsInt16Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsUInt16Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsInt32Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsUInt32Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsFloat32Array, True));
  mResult.Lines.Add(BoolToStr(jsArr.asObject.IsFloat64Array, True));
  mResult.Lines.Add('---------------------------');
  jsArr.asObject.GetArrayLength(cx, Cnt);
  mResult.Lines.Add(IntToStr(Cnt));
  jsArr.asObject.GetElement(cx, 0, jsArrElement);
  mResult.Lines.Add(BoolToStr(jsArrElement.isInteger, True));
  mResult.Lines.Add(BoolToStr(jsArrElement.isDouble, True));
  mResult.Lines.Add(BoolToStr(jsArrElement.isNumber, True));
  mResult.Lines.Add(BoolToStr(jsArrElement.isSimpleVariant[cx], True));
  mResult.Lines.Add('###########################');

  Result := True;
end;

#88 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-13 16:47:21

Thank you for your patience and efforts to explain ! smile Too dumb to realize that the null terminator has to be two bytes in UTF-16 (also shown here http://stackoverflow.com/questions/2685730/) big_smile

https://www.securecoding.cert.org/confl … terminated
The first paragraph of the link above states "...... UTF-16 strings may contain \u0000 in the middle of the string, ......", but still, for UTF-16, the u'\0' is two bytes .

#89 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-13 16:07:40

ab wrote:

???
There is no such thing as an "UTF-8 char", and Dest^ := #0 is setting only a single byte in the latest position, which is already reserved by TSynTempBuffer.Init:

GetMem(buf,len+1); // +1 to include trailing #0

I should be more precise: characters encoded with UTF8.
I see your point. Now I feel lost again why mpv's fix works... yikes

#90 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-13 15:45:25

mpv wrote:

Issue fixed by [d66449a2c4]. Thanks for reporting!
@AB - please, review the RawUnicodeToUtf8 function - may be we need to allocate one more byte there also?

 tmp.Init(WideCharCount*3+1); 

instead of 

 tmp.Init(WideCharCount*3); 

Dear @mpv, thank you very much for your efforts ! The fix looks too fundamental to the framework to believe !... big_smile

ab wrote:

Thanks for the input.

I guess that RawUnicodeToUtf8() is safe, since its output is 8-bit content, so trailing #0 is stored as a single 0 byte.

Dear @ab,

function RawUnicodeToUtf8(Dest: PUTF8Char; DestLen: PtrInt; Source: PWideChar;
  SourceLen: PtrInt; Flags: TCharConversionFlags): PtrInt; overload;
  ......
  result := PtrInt(Dest);
  inc(DestLen,PtrInt(Dest));
  ......
    if (PtrInt(Dest)<DestLen) and (PtrInt(Source)<SourceLen) then
    repeat
      ......
    until false;
    if not (ccfNoTrailingZero in Flags) then
      Dest^ := #0;

as shown in SynCommons, if all UTF8 chars converted need 3 bytes to store, Dest^ := #0; is essentially setting the WideCharCount*3+1 th position instead of the WideCharCount*3 th position. Is this right ? It seems that @mpv has a good point here. yikes

#91 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-12 09:14:26

It seems that the memory footer corruption can be avoided with some modification of TSynTempBuffer to avoid the re-allocation in TSynTempBuffer.Init. The reason is unclear. Could ab or you help to correct the root problem ?

  private
    // tmp: array[0..4095] of AnsiChar; <--- memory footer corruption
    // 
    // for 'mORMot\SyNode\Samples\02 - Bindings\SpiderMonkey45Binding.dpr', 
    // where 'mORMot\SyNode\core_modules\DevTools\Debugger.js' will be loaded
    // = Length of 'mORMot\SyNode\core_modules\DevTools\Debugger.js' * 2 + 1 
    tmp: array[0..118038] of AnsiChar; 
    //
    // if only the files 'mORMot\SyNode\core_modules\node_modules\' are to be loaded
    // = Length of NativeModule.wrap('mORMot\SyNode\core_modules\node_modules\util.js') * 2 + 1 
    // tmp: array[0..33584] of AnsiChar; 
  end;

#92 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-12 01:07:03

mpv wrote:

This idea is obsolete. At last, SM45 require nspr. Actually, Im not understand your problem.personnaly I did use fastmm in full debug mode may be several time during last 10 years. Even in non full debug mode fastmm can detect a memory leak very well.

FastMM with FullDebugMode on can give the call stack trace with line numbers leading to the individual memory leak. Could you comment whether you use this feature, and if yes, how to work around ? Many thanks for your efforts to share your experience ! big_smile (It should be mentioned that FastMM with FullDebugMode on is also very useful to track any buffer overflow, again, with the call stack trace with line numbers .)

#93 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2016-10-11 16:15:45

Dear mpv,

http://synopse.info/forum/viewtopic.php?id=3544
http://synopse.info/forum/viewtopic.php?id=3571

In the links above, you have identified that there should be a conflict between FastMM in FullDebug mode and a nspr memory manager (SpiderMonkey use a memory manager from Netscape Portable Run-time nspr4.dll).

However, FullDebugMode is needed for FastMM to log all memory leaks to a text file, and therefore rather important for finding memory leaks.

In SynSMAPI.pas, there is mentioned "compile mozjs without nspr" under "road map". Does this mean that this incompatibility between FastMM w/ FullDebugMode and SpiderMonkey will be removed in future ?  big_smile

#94 Re: mORMot 1 » Exception raised in TestSynSM: error during FreeMem operat » 2016-10-05 14:11:18

mpv wrote:

Yes, we also reproduce a FreeMem error in case FastMM FullDebugMode enabled. At the moment we do not know the reason

Thank you very much for your efforts in researching ! I hope this issue could be resolved in future, because FullDebugMode is rather important for FastMM for finding memory leaks.

#95 Re: mORMot 1 » Exception raised in SpiderMonkey45Binding: error during FreeMem operat » 2016-10-05 14:09:58

mpv wrote:

We reproduce a issue - this is because FastMM FullDebugMode

{$IFDEF DEBUG} {$define FullDebugMode} {$ENDIF}

is enabled in your FastMM4Options.inc
Without this option enabled everything is fine. At the moment we do not know the reason. Looks like a conflict between FastMM in FullDebug mode and a nspr memory manager (SpiderMonkey use a memory manager from Netscape Portable Run-time nspr4.dll)

Thank you very much for your efforts in researching ! Because FullDebugMode is rather important for FastMM for finding memory leaks, I hope this incompatibility between FastMM w/ FullDebugMode and SpiderMonkey could be removed in future. big_smile

#97 mORMot 1 » Exception raised in TestSynSM: error during FreeMem operat » 2016-10-01 17:18:50

ComingNine
Replies: 2

Using mORMot '1.18.3006', if compiled with Delphi 7 with FastMM FullDebugMode enabled, TestSynSM gives various errors when run second time, i.e., when js/jslint.js already exists. Could you help to check ?

The screen shots can be seen at imgur.

https://imgur.com/a/1M7B4

The content of TestSynSM log is

https://gist.github.com/anonymous/fce89 … 71ec1bed94

The content of TestSynSM_MemoryManager_EventLog.txt is

https://gist.github.com/anonymous/0155c … 7f27be26e2

The content of FastMM4Options.inc used is

https://gist.github.com/anonymous/5ebb8 … f1240e28ea

PS: If compiled with Delphi 7 without  FastMM FullDebugMode enabled, TestSynSM runs fine no matter how many times.

PS: If compiled with Delphi XE, XE8 or Berlin, TestSynSM runs fine no matter how many times.

#98 Re: mORMot 1 » Exception raised in SpiderMonkey45Binding: error during FreeMem operat » 2016-09-25 07:09:58

mpv wrote:

I'll check tomorrow

Can you comment whether you can at least reproduce this issue ?

#99 Re: mORMot 1 » Exception raised in TestSynSM: TSMEngine error: [JSError 110] mustache » 2016-09-23 07:16:08

mpv wrote:

I fix a warning - actually this is a bug in our test. See [a30165310f]
I'm totally not understand why it raised only if debugger is off. AFAIR autotest do some hack for errors handling in debuger mode, but can't find where

Thank you for fixing the code and committing the change to trunk!

About the exception when debugger is off: do you mean ab might know all the details ? big_smile

#100 Re: mORMot 1 » Exception raised in TestSynSM: TSMEngine error: [JSError 110] mustache » 2016-09-22 16:05:26

Thank you very much for your efforts !
Can you help to comment : (1) Why the exception only is raised for certain circumstances (for D7, outside IDE; for latest versions, without debugger) ? (2) Is this test-failing expected ?

Board footer

Powered by FluxBB