dws-developer Mailing List for DelphiWebScript
Brought to you by:
hhernler,
mackermann
You can subscribe to this list here.
2003 |
Jan
|
Feb
(3) |
Mar
(35) |
Apr
(6) |
May
(15) |
Jun
(6) |
Jul
(11) |
Aug
(66) |
Sep
(11) |
Oct
(6) |
Nov
(5) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
(27) |
Feb
|
Mar
|
Apr
(4) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Mark <mnm...@co...> - 2004-04-19 02:49:29
|
Andreas! Glad to hear from you. :) Andreas Luleich wrote: [...] > We discussed the problem here at work, but we found no practical > solution for it. We have wrapped some TComponent classes. We collect all > objects that we must "auto-destroy" under a special Owner-component. > That is our criterion. The only "elegent" way I could think of using was to change the descendent class like this... <DELPHI-CURRENT> TMeth_TFileStream_Create = class(TAnonymousMethod, ICallable) procedure Execute(var ExternalObject: TObject); override; end; </DELPHI-CURRENT> to something like this... <DELPHI-POSSIBLE> TMeth_TFileStream_Create = class(TAnonConstructorMethod, ICallable) procedure Execute(var ExternalObject: TObject; var AutoDestroy: Boolean); override; end; </DELPHI-POSSIBLE> The difference is a new ancestor type that introduces an overriden Execute() method that tracks if it should auto-destroy the instance when created. The problem is that this is only working through the ICallable interface and that doesn't seem to be easily worked in. If you can think of a nice way to do this I'd love to try it. When I generate the code I can test for a constructor type and hook it up differently if we can find how to hook it up. Then, where would the AutoDestroy value get stored? I would think on the ScriptObject. But it just calls the hooked up OnDestroy event. That might need to be changed too to add an extra param for destruction info. Or if it passes "Self" then the event could look at the ScriptObj and say "Ah, I must auto destroy your Delphi object." Or something. > > Another possible solution might be to define a derivation of the class > you are wrapping: > > type TFileStream_sfx = class (TFileStream); > > The Create-Wrapper: > if not Assigned(ExternalObject) then > ExternalObject := TFileStream_sfx.Create(...) > > The Destroy-Wrapper: > if ExternalObject is TFileStream_sfx then > FreeAndNil(ExternalObject); Yes, this is another option. I'd prefer not to do this, for obvious reasons, but short of a better solution I could try. > If anyone else gets a better solution, please tell it here ... Amen. :) -Mark E. |
From: Andreas L. <alu...@we...> - 2004-04-18 21:06:56
|
> The problem is that the script object's constructor implemented through > the TMeth_TFileStream_Create class. The real issue is that if the > instance is ALREADY created (ie. RegisterExternalObject) then we DON'T > want the script object to destroy it when it scopes out. I don't have > any way to add a flag to say "Yes, I want this instance auto-cleaned up." Hi Mark, not only you have been quiet ;) We discussed the problem here at work, but we found no practical solution for it. We have wrapped some TComponent classes. We collect all objects that we must "auto-destroy" under a special Owner-component. That is our criterion. Another possible solution might be to define a derivation of the class you are wrapping: type TFileStream_sfx = class (TFileStream); The Create-Wrapper: if not Assigned(ExternalObject) then ExternalObject := TFileStream_sfx.Create(...) The Destroy-Wrapper: if ExternalObject is TFileStream_sfx then FreeAndNil(ExternalObject); If anyone else gets a better solution, please tell it here ... ALu |
From: Mark <mnm...@co...> - 2004-04-15 03:16:20
|
Andreas & others, Mark here. I've been quiet, I know. I was trying to add fix the destructor issue that we discussed some time ago. Here is the problem as I see it. Any insight or direction is appreciated. Taken from dws2ClassesLib.pas: <DELPHI> TMeth_TFileStream_Create = class(TAnonymousMethod, ICallable) procedure Execute(var ExternalObject: TObject); override; end; [...] procedure TMeth_TFileStream_Create.Execute; begin //constructor TFileStream.Create(const FileName: String; Mode: Integer); if not Assigned(ExternalObject) then ExternalObject := TFileStream.Create(Info['FileName'], Info['Mode']); end; </DELPHI> The problem is that the script object's constructor implemented through the TMeth_TFileStream_Create class. The real issue is that if the instance is ALREADY created (ie. RegisterExternalObject) then we DON'T want the script object to destroy it when it scopes out. I don't have any way to add a flag to say "Yes, I want this instance auto-cleaned up." I've looked into changing some code in dws2Functions.pas for TAnonymousMethod.Call(...) to test if we are about to call a constructor and the ExternalObject goes from "nil" to "not nil" then flag the IScriptObject as needing to free the class. However, this is a nasty hack and is very ugly. I hate ugly code and I hate even more writing it! If you can point me to a better solution I would really appreciate it. I really do want to fix it the right way. It is an issue for me when you have a TFileStream and the Delphi object instance isn't freed until the Host application closes. It ends up holding locks on the file. -Mark E. |
From: Mark <mnm...@co...> - 2004-04-14 03:07:38
|
Andreas & others, Mark here. I've been quiet, I know. :) I was trying to add fix the destructor issue that we discussed some time ago. Here is the problem as I see it. Any insight or direction is appreciated. Taken from dws2ClassesLib.pas: <DELPHI> TMeth_TFileStream_Create = class(TAnonymousMethod, ICallable) procedure Execute(var ExternalObject: TObject); override; end; [...] procedure TMeth_TFileStream_Create.Execute; begin //constructor TFileStream.Create(const FileName: String; Mode: Integer); if not Assigned(ExternalObject) then ExternalObject := TFileStream.Create(Info['FileName'], Info['Mode']); end; </DELPHI> The problem is that the script object's constructor implemented through the TMeth_TFileStream_Create class. The real issue is that if the instance is ALREADY created (ie. RegisterExternalObject) then we DON'T want the script object to destroy it when it scopes out. I don't have any way to add a flag to say "Yes, I want this instance auto-cleaned up." I've looked into changing some code in dws2Functions.pas for TAnonymousMethod.Call(...) to test if we are about to call a constructor and the ExternalObject goes from "nil" to "not nil" then flag the IScriptObject as needing to free the class. However, this is a nasty hack and is very ugly. I hate ugly code and I hate even more writing it! ;) If you can point me to a better solution I would really appreciate it. I really do want to fix it the right way. It is an issue for me when you have a TFileStream and the Delphi object instance isn't freed until the Host application closes. It ends up holding locks on the file. -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-22 22:43:04
|
I checked in CVS where I - introduced Assigned (for objects and function type vars) - reintroduced TObject.Free I will give some extended comments next days (too tired ...), sorry. ALu PS1: Mark, I will comment your mail at a later time (this weekend). There seem to be some problems with cvs.sf.net ... I cannot see your changes. PS2: Developers, may be you can do some tests or give some comments ("REJECT IT!") before I drop a note to the forum about my changes. Thanks. |
From: Mark <mnm...@co...> - 2004-01-22 06:34:29
|
Mark wrote: [...] >>"sl is TStringList" also results to "False". First check of the >>"is"-operator is the test "pointer=nil?" (see CPU Window). So I think >>there is no need for the nil check. > > > > You are, of course, correct. Sorry I missed that. I'll change that later. Thanks. :) This has been changed in CVS in dws2PasGenerator.pas (rev 1.9). [...] > At any rate you are correct. I will change the code generator to CREATE differently. This has also been changed in CVS (same file). The VclWrappers units have been regenerated too. Here is a code sample to illustrate. <DELPHI> procedure TMeth_TStringList_Create.Execute; begin //constructor TStringList.Create; if not Assigned(ExternalObject) then <==new ExternalObject := TStringList.Create; end; procedure TMeth_TStringList_Add.Execute; begin //function TStringList.Add(const S: String): Integer; Assert(ExternalObject is TStringList); <==optimized Info.Result := TStringList(ExternalObject).Add(Info['S']); end; </DELPHI> As for the issues with the .RegisterExternalObject() not calling the constructor that is still a valid issue. As noted in my previous email, it is an issue with many of the existing libraries not checking the external object before assigning it. Either we need to replace or update the existing libraries. > Now, about the destructors... [...] I'm still unclear on how to resolve this issue. If I need to include Destructors I can easily do that for the Delphi objects that included their own (sometimes not overriden in the wrapped class). But I still don't understand why it is needed. Thanks for you help and patience. -Mark E. |
From: Mark <mnm...@co...> - 2004-01-16 19:44:38
|
Andreas Luleich wrote: >> var>> sl: TStringList; >> someObject: TObject; >> begin >> sl := nil; >> someObject := sl; >> >> if someObject is TStringList then >> showMessage('I''m a TStringList'); >> end; >> >> Using D5, the message does not show. >> > > "sl is TStringList" also results to "False". First check of the > "is"-operator is the test "pointer=nil?" (see CPU Window). So I think > there is no need for the nil check. You are, of course, correct. Sorry I missed that. I'll change that later. Thanks. :) >> Hmm. I think this would work better: (haven't tried it... could be wrong) >> >> Info.Result := Info.RegisterExternalObject(TMyStringList.Create, True, >> False); >> > > Yes, this may work. But I (as user) would NEVER understand, why NO > constructor is called, when creating a new object. That's why I am not a > fan of "your" RegisterExternalObject function (Sorry). A similar > question is unanswered in the forum (2003/12/21 "Why doesn't the > constructor get called?"). I do not have a convincing answer ... :( As you noted before, the wrapped TMeth_TStringList_Create overwrites the object. Without having tested it, would it be better to change it this way? procedure TMeth_TStringList_Create.Execute; begin //constructor TStringList.Create; if not Assigned(ExternalObject) then <== added ExternalObject := TStringList.Create; end; I just tested this and it works the way you want it. However, *many* of the dws2\Libraries do not do this test. When I was first working on it I thought that calling the script objects constructor would *always* create the Delphi object instance. Which is not what I wanted. I may be remembering wrong, but I thought there were problems with the way the ExtObject was passed in. I may have been wrong or it may have changed. At any rate you are correct. I will change the code generator to CREATE differently. However, there is still the issue of the existing Libraries and how they create objects. This is the case for Ibx and Db (two that I checked on). My "RegisterExternalObject" got around the issue by not calling the constructor. Maybe that was a bad thing, but when I first started on DWS I was (and still am) very hesitent about making core changes as I don't have the depth of knowledge that you and others have. If we fix the libraries or replace them with new wrappers then it will all be okay. Then we can change the RegisterExternalObject method to call the constructor. This could still cause problems for people who have created their own wrappers where they didn't do the test either. Any other thoughts on this? ========= Now, about the destructors... >> This was intentional. I thought that declaring the destructor was >> wasted memory (extra symbols) because all you need to do is call .Free >> and TObject implements that. Was I wrong to do this? Does *every* >> class need a destructor or is an ancestor declared one okay? > > > I like the idea to reintroduce the Free-Method (copy-paste of Delphi > code ;) ). > If no one of the developers raises an objection ... I can start a try > (hello Matthias?). But for your problem: Sometimes I take quasi-fix > objects as ExternalObjects (the current form, a button, ttable, tgrid, > etc.) Such an object must not freed at destruction of the IScriptObj. So > a general destruction of the ExternalObject in "TObject.Destroy" (DWS) I > will not support. I would introduce a new flag in TScriptObj?! I personally like the garbage collection ability. I've gotten very used to it. ;) You could add a .Free method that didn't do ANYTHING but would keep it compilable. Now, here is an idea that may be totally wrong but here goes... Could you introduce a .Free() method that simply nilled the script object interface reference? This would have a similar effect in most cases. There might be an unexpected behavior in the following script... <SCRIPT> var sl: TStringList = TStringsList.Create; try sl.Add('Thing'); finally sl.Free; end; sl.Clear; </SCRIPT> What I'm not sure of is how the "sl" would be treated. If that variables reference to the object was nilled then it would correctly cause an error. If there was another reference to the interface somehow then the object would stay alive and the "sl.Clear;" would error but the object would still exist? I don't know. Just a thought. The reason I didn't include any Destroy wrappers was that the DWS type "TObject" includes a destructor. So I thought that finding the method name "Destroy" would *always* work and since you never call a (Delphi) TStringList.Destroy method that it made sense to not include the wrapped method. After all, if the wrapped Destroy method DID exist I wouldn't want it to be called! So what do I do about the Destroy? What type of change is needed? I'm still not completely clear on it. :) -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-16 15:44:33
|
<html><style>p {margin: 0px}</style><body style='font-size:9pt; font-family:Verdana; font-family: Verdana' ><P>OK, what you have defined in your dws2Unit is equivalent written in code:</P><P>type LongMonthNames = array [1 .. 12] of String;</P><P>(please have look at the first word!)</P><P>You cannot have indexed access to LongMonthNames -> LongMonthNames[i]. You must declare a variable of that type:</P><P>type TLongMonthNames = array [1 .. 12] of String;</P><P>var LongMonthNames : TLongMonthNames;</P><P>Here indexed access should be possible.</P><P>ALu</P><P> </P><P> </P></body></html> ______________________________________________________________________________<br>Erdbeben im Iran: Zehntausende Kinder brauchen Hilfe. UNICEF hilft den<br>Kindern - helfen Sie mit! https://www.unicef.de/spe/spe_03.php |
From: Wilbert v. L. <w.v...@ks...> - 2004-01-16 15:17:11
|
Andreas, further clarification ... Consider function Tdws2Compiler.ReadName(IsWrite: Boolean): TExpr; // Find name in symboltable sym := FProg.Table.FindSymbol(Name); try baseType := GetBaseType(sym); Now what happens if the baseType = TStaticArraySymbol? else if sym is TDataSymbol then begin Result := ReadSymbol(GetVarExpr(TDataSymbol(sym)), IsWrite); end else if sym is TExternalVarSymbol then Result := ReadSymbol(ReadExternalVar(TExternalVarSymbol(sym), IsWrite), IsWrite) // OOP related stuff else if baseType is TClassSymbol then begin It falls through everything, until it comes to this line: else if sym is TTypeSymbol then Result := ReadTypeCast(namePos, sym) else and then it will throw the exception that it needs the '(' as expected in a typecast instead of the '[' as expected in a indexing operation because TStaticArraySymbol is a descendant of TTypeSymbol Best regards, Wilbert |
From: Andreas L. <alu...@we...> - 2004-01-16 15:14:00
|
<html><style>p {margin: 0px}</style><body style='font-size:9pt; font-family:Verdana; font-family: Verdana' ><P>Ok, lets express it in DFM:</P><P> object dws2Unit: Tdws2Unit<BR> Arrays = <<BR> item<BR> Name = 'TLongMonthNames'<BR> DataType = 'String'<BR> LowBound = 1<BR> HighBound = 12<BR> end><BR> Variables = <<BR> item<BR> Name = 'LongMonthNames'<BR> DataType = 'TLongMonthNames'<BR> end><BR>[...]</P><P>Regards, ALu.</P><P> </P><P>"Wilbert van Leijen" <w.v...@ks...> schrieb am 16.01.04 16:06:34:<BR><BR>Adreas,<BR><BR>Thanks for the speedy r! eply.<BR><BR>But I think you misunderstood me, unless I have overlooked the possibility<BR>to enter Type definitions in a Tdws2Unit!<BR>The array LongMonthNames is on a form, like this:<BR><BR>object ScriptDM: TScriptDM<BR>OldCreateOrder = False<BR>Left = 6<BR>Top = 572<BR>Height = 159<BR>Width = 265<BR>object Script: TDelphiWebScriptII<BR>Config.CompilerOptions = []<BR>Config.MaxDataSize = 0<BR>Config.Timeout = 0<BR>Left = 16<BR>Top = 8<BR>end<BR>object ExtraUnit: Tdws2Unit<BR>Script = Script<BR>Arrays = <<BR>item<BR>Name = 'LongMonthNames'<BR>DataType = 'String'<BR>LowBound = 1<BR>HighBound = 12<BR>end<BR><BR>(etc)<BR><BR><BR><BR>----- Original Message ----- <BR>From: "Andreas Luleich" <alu...@we...><BR>To: "DWS Developer" <dws...@li...><BR>Sent: Friday, January 16, 2004 3:54 PM<BR>Subject: Re: [dws-developer] Bug in Tdws2Compiler.ReadName<BR><BR><BR>> Hi Wilbert,<BR>><BR>> you defined only a type of an array (like: type L! ongMonthNames =<BR>array[1..12] of String; ). You must define a variab le of that type (type<BR>TLongMonthNames = array[1..12] of String; var LongMonthNames :<BR>TLongMonthNames;) .<BR>><BR>> ALu<BR>><BR>> PS: In my test I got an error "Can't assign value to left side." when<BR>writing<BR>><BR>> LongMonthNames[i] := ...<BR>><BR>> I will have a look at the code to enable write access. Its my fault :(<BR><BR><BR><BR></P></body></html> ______________________________________________________________________________<br>Nachrichten, Musik und Spiele schnell und einfach per Quickstart im <br>WEB.DE Screensaver - Gratis downloaden: <A HREF="http://screensaver.web.de/?mc=021110"><B>http://screensaver.web.de/?mc=021110</B></A> |
From: Andreas L. <alu...@we...> - 2004-01-16 14:54:46
|
Hi Wilbert, you defined only a type of an array (like: type LongMonthNames = array[1..12] of String; ). You must define a variable of that type (type TLongMonthNames = array[1..12] of String; var LongMonthNames : TLongMonthNames;) . ALu PS: In my test I got an error "Can't assign value to left side." when writing LongMonthNames[i] := ... I will have a look at the code to enable write access. Its my fault :( ______________________________________________________________________________ Erdbeben im Iran: Zehntausende Kinder brauchen Hilfe. UNICEF hilft den Kindern - helfen Sie mit! https://www.unicef.de/spe/spe_03.php |
From: Wilbert v. L. <w.v...@ks...> - 2004-01-16 14:37:27
|
Gents, Here is the scenario - I have added an array in my Tdws2Unit descendant: LongMonthNames. It is now a part of MyUnit.Arrays. I could not get a script compiled wherein I used LongMonthnames. It kept on whining about a missing '(' where I put the '[' for i := 1 to 12 do LongMonthNames[i] := ... (Actually, the array is initialised elsewhere, but that is not important now.) Problem can be traced back to Tdws2Compiler.ReadName: there is no proviso for symbols of class TStaticArraySymbol. So it falls through until it reaches TTypeSymbol (TStaticArraySymbol is derived from this class) and then the parser thinks that my array is a typecast: else if sym is TFuncSymbol then Result := ReadSymbol(ReadFunc(TFuncSymbol(sym), IsWrite), IsWrite) // Type casts else if sym is TTypeSymbol then Result := ReadTypeCast(namePos, sym) ^--- EScriptError is triggered here else FMsgs.AddCompilerStop(FTok.HotPos, Format(CPE_UnknownType, [sym.Caption])); Question: how do I resolve this situation? Best regards, Wilbert |
From: Andreas L. <alu...@we...> - 2004-01-15 23:49:34
|
Mark wrote: >> Third I think that assertion questions like >> >> Assert((ExternalObject<>nil) and (ExternalObject is TStringList)); >> >> can be optimized to >> >> Assert(ExternalObject is TStringList); >> >> Am I right? >> >> OK, time to go to bed ..., ALu. > > > No. I had to double check to make sure. Here is some Delphi code to try > out. > > var > sl: TStringList; > someObject: TObject; > begin > sl := nil; > someObject := sl; > > if someObject is TStringList then > showMessage('I''m a TStringList'); > end; > > Using D5, the message does not show. > "sl is TStringList" also results to "False". First check of the "is"-operator is the test "pointer=nil?" (see CPU Window). So I think there is no need for the nil check. > Hmm. I think this would work better: (haven't tried it... could be wrong) > > Info.Result := Info.RegisterExternalObject(TMyStringList.Create, True, > False); > Yes, this may work. But I (as user) would NEVER understand, why NO constructor is called, when creating a new object. That's why I am not a fan of "your" RegisterExternalObject function (Sorry). A similar question is unanswered in the forum (2003/12/21 "Why doesn't the constructor get called?"). I do not have a convincing answer ... :( > This was intentional. I thought that declaring the destructor was wasted > memory (extra symbols) because all you need to do is call .Free and > TObject implements that. Was I wrong to do this? Does *every* class need > a destructor or is an ancestor declared one okay? I like the idea to reintroduce the Free-Method (copy-paste of Delphi code ;) ). If no one of the developers raises an objection ... I can start a try (hello Matthias?). But for your problem: Sometimes I take quasi-fix objects as ExternalObjects (the current form, a button, ttable, tgrid, etc.) Such an object must not freed at destruction of the IScriptObj. So a general destruction of the ExternalObject in "TObject.Destroy" (DWS) I will not support. I would introduce a new flag in TScriptObj?! Regards, ALu. |
From: Mark <mnm...@co...> - 2004-01-15 05:03:03
|
Andreas Luleich wrote: > Hi Mark, > > I played a bit with the TStringList wrapper implementation and found > something to tell you. > > First there is no destructor defined and implemented for any(?) of your > implementation. So the (single line) script > > <SCRIPT> > TStringList.Create; > </SCRIPT> This was intentional. I thought that declaring the destructor was wasted memory (extra symbols) because all you need to do is call .Free and TObject implements that. Was I wrong to do this? Does *every* class need a destructor or is an ancestor declared one okay? > Second I often create objects within unit functions: > > <UNIT> > function CreateStringList : TStringlist; > </UNIT> > > and call GetConstructor(..) in OnEval: > > <DELPHI> > type TMyStringList = class (TStringList); > > procedure TFDwsDemo.dws2Unit1FunctionsCreateStringListEval( > Info: TProgramInfo); > begi > Info.Result := Info.Vars['TStringList'].GetConstructor( > 'Create',TMyStringList.Create).Call.Value; > end; > </DELPHI> Hmm. I think this would work better: (haven't tried it... could be wrong) Info.Result := Info.RegisterExternalObject(TMyStringList.Create, True, False); The final param is ExactMatch. If False, it should go through the objects ancestry to find a match that DWS knows about. This would end up as a TStringList. > Third I think that assertion questions like > > Assert((ExternalObject<>nil) and (ExternalObject is TStringList)); > > can be optimized to > > Assert(ExternalObject is TStringList); > > Am I right? > > OK, time to go to bed ..., ALu. No. I had to double check to make sure. Here is some Delphi code to try out. var sl: TStringList; someObject: TObject; begin sl := nil; someObject := sl; if someObject is TStringList then showMessage('I''m a TStringList'); end; Using D5, the message does not show. Thanks again for the help. I'll have to test it at work tomorrow. :) Assume it works, if not I'll come yelling. ;) -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-15 00:20:49
|
Hi Mark, I played a bit with the TStringList wrapper implementation and found something to tell you. First there is no destructor defined and implemented for any(?) of your implementation. So the (single line) script <SCRIPT> TStringList.Create; </SCRIPT> leaves something in memory (the delphi stringlist). Second I often create objects within unit functions: <UNIT> function CreateStringList : TStringlist; </UNIT> and call GetConstructor(..) in OnEval: <DELPHI> type TMyStringList = class (TStringList); procedure TFDwsDemo.dws2Unit1FunctionsCreateStringListEval( Info: TProgramInfo); begin Info.Result := Info.Vars['TStringList'].GetConstructor( 'Create',TMyStringList.Create).Call.Value; end; </DELPHI> This examples creates its own implementation of TStringList (TMyStringList), that is overwritten by your ExtObj-assignment in your constructor implementation (TMeth_TStringList_Create). I don't know whether this should be supported or not. Third I think that assertion questions like Assert((ExternalObject<>nil) and (ExternalObject is TStringList)); can be optimized to Assert(ExternalObject is TStringList); Am I right? OK, time to go to bed ..., ALu. |
From: Mark <mnm...@co...> - 2004-01-15 00:14:24
|
Andreas Luleich wrote: > Hi Mark, > > I found your reported bug. Problem was method TAnonymousMethod.Call in > dws2Functions.pas. Man, you are amazing! How did you do that? I appreciate it very much. Hope you didn't have to invest too much time into it. Thanks again! -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-14 23:35:51
|
Hi Mark, I found your reported bug. Problem was method TAnonymousMethod.Call in dws2Functions.pas. TAnonymousMethod.Call saved the "Self"-ScriptObject at call time to "FInfo.ScriptObj" (and did not reset it on finish). So the script object was not freed at end of the program (with static symbols in classeslib!), because there were references to the script object in any of the called "TAnonymous" objects. I fixed that and checked in CVS (dws2Functions.pas rev 1.8). Good luck, ALu. |
From: Mark <mnm...@co...> - 2004-01-14 20:42:58
|
I've hit an AV with the current CVS code (pulled today). It's been quite a while since I've pulled DWS from CVS at work (that's where I am now) so don't assume it is a recently created problem. I'm not sure if something is wrong with the my Tdws2ClassesLib component or not. This appears to be related to my wrapper. I would appreciate any help that can be offered. Script to demonstrate issue: <SCRIPT> var sl: TStringList; sl := TStringList.Create; sl.Add('This is a string.'); sl.Add('This is another.'); Print(sl.Text); </SCRIPT> To recreate: + Start with the Simple DWS demo. + Drop a Tdws2ClassesLib (from \dws2\Libraries\VclWrappers) on and hook to compiler. + Run app, and paste in above script. + Compile the program (nothing wrong) + Execute the program (nothing wrong) + Compile the program AGAIN. (AV error) I've traced the error down to here... dws2Symbols.pas function TSymbolTable.FindLocal(const Name: string): TSymbol; var x: Integer; begin Result := nil; // Lookup in Hot-list for x := 0 to SymbolCacheSize - 1 do if Assigned(FHot[x]) and (SameText(FHot[x].Name, Name)) then [...] end; The context is... Coming from "TProgram.DestroyScriptObj()" to destroy the TStringList object it calls "TSymbolTable.FindSymbol('Destroy')" which in turn calls the FindLocal method. The error is with the FHot array. One of the array indexes is invalid at this point and gives an AV. I'm not sure if I need to change the way code is generated and registered or what. Thanks in advance. -Mark E. |
From: Mark <mnm...@co...> - 2004-01-12 06:23:07
|
Mark wrote: [...] > Thanks for catching this and fixing the other leak. > > I'll fix the code generator then rebuild these units. ALu, I have fixed the dws2PasGenerator and then regenerated the VclWrappers. If you get a chance, please take a look to see that they are correct now. I believe enums are fixed and some other problems I ran into. Thanks! -Mark E. |
From: Mark <mnm...@co...> - 2004-01-08 05:26:03
|
Andreas Luleich wrote: > Hi Mark, > > while looking for memory leaks in DWS I found that creation of > enumeration symbols is incorrect in your wrapped VCL. Every(!) element > of the enumeration must be added to the symboltable. > [...] Thanks for catching this and fixing the other leak. I'll fix the code generator then rebuild these units. -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-07 20:06:19
|
Hi Mark, while looking for memory leaks in DWS I found that creation of enumeration symbols is incorrect in your wrapped VCL. Every(!) element of the enumeration must be added to the symboltable. // enum TAlignment = (taLeftJustify, taRightJustify, taCenter); enum := TEnumerationSymbol.Create('TAlignment', typ_Integer); SymbolTable.AddSymbol(enum); typ_TAlignment := enum; enum.AddElement(TElementSymbol.Create('taLeftJustify', typ_TAlignment, 0, False)); enum.AddElement(TElementSymbol.Create('taRightJustify', typ_TAlignment, 1, False)); enum.AddElement(TElementSymbol.Create('taCenter', typ_TAlignment, 2, False)); must be changed to: // enum TAlignment = (taLeftJustify, taRightJustify, taCenter); enum := TEnumerationSymbol.Create('TAlignment', typ_Integer); SymbolTable.AddSymbol(enum); typ_TAlignment := enum; elem := TElementSymbol.Create('taLeftJustify', typ_TAlignment,0, False); SymbolTable.AddSymbol(elem); enum.AddElement(elem); ... In your case 'taLeftJustify' is not found and remains as leak in memory because the enumeration symbol does not free its elements. ALu |
From: Andreas L. <alu...@we...> - 2004-01-06 19:43:50
|
I comitted the changes to get that running. The more simple script did also not work: // ----------- function T(const S : String): String; begin result := S; end; var A,B,C : String; A:='A'; B:='B'; C:=T(A+B); // failed here // C:=T('A'+'B'); // will/can be optimized Print(C); // ----------- I spent some time to optimize DWS for better results of the paxTests (forum post of Ray Mond at 10/20/2003 - Benchmarks) and I think we now could give "pass by value" another chance. I will tackle that problem next. Also I want to introduce an "assigned" function like length/high/low. I need it for callback/event-assign-requests. ALu |
From: Mark <mnm...@co...> - 2004-01-06 14:58:14
|
Andreas Luleich wrote: > Mark wrote: > >> sql.Add('CREATE TABLE ' + sessionTbl); > > > Nice problem. Thanks! Glad I could offer something of difficulty. ;) > Here DWS must create a temporary data expression ... I > will have a look at it and I will try not to introduce a "not supported" > exception as the easiest solution. I was thinking, because this is kind of an exception, maybe it can be done differently. Since it only is significant when calling a Tdws2Unit OnEval event perhaps we can just check the variant type and treat it differently as needed. If the variant type is string/int, etc then treat is as a "pass by value"? Maybe this doesn't work for this or it would still be broken for calling a procedure in a script (not using a Tdws2Unit). Just trying to offer something to help out. -Mark E. |
From: Andreas L. <alu...@we...> - 2004-01-06 00:33:13
|
Mark wrote: > sql.Add('CREATE TABLE ' + sessionTbl); Nice problem. Here DWS must create a temporary data expression ... I will have a look at it and I will try not to introduce a "not supported" exception as the easiest solution. ALu |
From: Mark <mnm...@co...> - 2004-01-05 18:42:17
|
In case it matters, this is in D5. Shouldn't matter though. The error is an EVariantError with message of 'Invalid variant type conversion'. The script looks like this... var sql: TStringList = TStringList.Create; var sessionTbl: string = 'STUFFY'; sql.Add('CREATE TABLE ' + sessionTbl); sql.Add('('); sql.Add(');'); Print(sql.Text); ============================================= The OnEval code (in the Libraries\VclWrappers\dws2ClassesLib.pas file) looks like this... procedure TMeth_TStringList_Add.Execute; begin //function TStringList.Add(const S: String): Integer; Assert((ExternalObject<>nil) and (ExternalObject is TStringList)); Info.Result := TStringList(ExternalObject).Add(Info['S']); end; ============================================= The problem appears in dws2Exprs.pas here... function TProgramInfo.GetVars(s: string): IInfo; [...] if sym is TVarParamSymbol then begin // Local or global variable vpd := IVarParamData(IUnknown(FCaller.Stack.Data[basePointer + TDataSymbol(sym).StackAddr])); Result := TInfo.SetChild(Self, sym.Typ, vpd.Data, vpd.Addr); end else [...] The issue is with the "vpd := " assignment. The script param is declared as a 'const' so it is a TVarParamSymbol but the FCaller.Stack.Data[ # ] evaluates to the actual string and not an object like I think it is expecting. The whole statement fails with the EVariantError exception. ============================================== It will work if the script is changed to this... var sql: TStringList = TStringList.Create; var sessionTbl: string = 'STUFFY'; var temp: string = 'CREATE TABLE ' + sessionTbl; sql.Add(temp); sql.Add('('); sql.Add(');'); Print(sql.Text); ---- The variable is evaluated before being passed as a "const" to the stringlist. ---- I don't feel confident with fixing this part unguided. Any help would be appreciated. -Mark E. |