xtool/contrib/mORMot/SyNode/SyNodeProto.pas

714 lines
22 KiB
ObjectPascal

/// SyNodeProto - create a JS prototypes for Delphi classes based on Delphi7 RTTI
// - this unit is a part of the freeware Synopse framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit SyNodeProto;
{
This file is part of Synopse framework.
Synopse framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - http://synopse.info
SyNode for mORMot Copyright (C) 2022 Pavel Mashlyakovsky & Vadim Orel
pavel.mash at gmail.com
Some ideas taken from
http://code.google.com/p/delphi-javascript
http://delphi.mozdev.org/javascript_bridge/
*** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Initial Developer of the Original Code is
Pavel Mashlyakovsky.
Portions created by the Initial Developer are Copyright (C) 2014
the Initial Developer. All Rights Reserved.
Contributor(s):
- Arnaud Bouchez
- Vadim Orel
- Pavel Mashlyakovsky
- win2014
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****
Version 1.18
- initial release. Use SpiderMonkey 45
}
interface
{$I Synopse.inc} // define HASINLINE
{$I SyNode.inc}
uses
{$ifdef ISDELPHIXE2}System.SysUtils,{$else}SysUtils,{$endif}
mORMot,
SynCommons,
SynLog,
SpiderMonkey;
type
TSMRTTIPropCache = record
mbr: pointer;//TRttiMember;
jsName: AnsiString;
isReadOnly: boolean;
DeterministicIndex: integer; // if not deterministic then -1
typeInfo: Pointer;//PTypeInfo;
end;
PSMRTTIPropCache = ^TSMRTTIPropCache;
TPropArray = array of TSMRTTIPropCache;
{$ifdef UNICODE}
TSMMethodRec = record
{$else}
TSMMethodRec = object
{$endif}
ujsName: SynUnicode;
method: pointer;
isNativeCall: boolean;
call: JSNative;
nargs: uintN;
flags: TJSPropertyAttrs;
end;
PSMMethodRec = ^TSMMethodRec;
TSMMethodDynArray = array of TSMMethodRec;
TSMObjectType = (otProto, otInstance, otOther);
{$ifdef UNICODE}
TSMObjectRecord = record
{$else}
TSMObjectRecord = object
{$endif}
Magic: Word;
DataType: TSMObjectType;
Data: Pointer;
procedure init(aDataType: TSMObjectType; aData: Pointer);
function IsMagicCorrect: boolean;
end;
PSMObjectRecord = ^TSMObjectRecord;
TSMCustomProtoObject = class;
TSMCustomProtoObjectClass = class of TSMCustomProtoObject;
PSMInstanceRecord = ^TSMInstanceRecord;
TFreeInstanceRecord = procedure (aInstanceRecord: PSMInstanceRecord);
{$ifdef UNICODE}
TSMInstanceRecord = record
{$else}
TSMInstanceRecord = object
{$endif}
private
function InternalCreate(cx: PJSContext; AInstance: TObject; AProto: TSMCustomProtoObject): jsval;
public
proto: TSMCustomProtoObject;
instance: TObject;
OwnInstance: Boolean;
AddData: pointer;
onFree: TFreeInstanceRecord;
procedure freeNative;
function CreateNew(acx: PJSContext; AProto: TSMCustomProtoObject; argc: uintN; var vp: JSArgRec): jsval;
function CreateForObj(acx: PJSContext; AInstance: TObject; AProto: TSMCustomProtoObjectClass; aParent: PJSRootedObject): jsval; overload;
function CreateForObj(acx: PJSContext; AInstance: TObject; AProto: TSMCustomProtoObjectClass; aParentProto: TSMCustomProtoObject): jsval; overload;
end;
TSMCustomProtoObject = class
private
fFirstDeterministicSlotIndex: uint32;
FJSClass: JSClass;
FJSClassProto: JSClass;
fSlotIndex: integer;
function getRTTIPropsCache(index: integer): TSMRTTIPropCache;
protected
fCx: PJSContext;
FjsObjName: AnsiString;
fRttiCls: TClass;
FJSProps: TJSPropertySpecDynArray;
fDeterministicCnt: uint32;
FRTTIPropsCache: TPropArray;
FMethods: TSMMethodDynArray;
FMethodsDA: TDynArrayHashed;
function GetJSClass: JSClass; virtual;
procedure InitObject(aParent: PJSRootedObject); virtual;
/// Add method to internal FMethods array for future define it into JS prototype
// to be called only inside InitObject method!
procedure definePrototypeMethod(const ajsName: SynUnicode; const aCall: JSNative; aNargs: uintN; aFlags: TJSPropertyAttrs);
property SlotIndex: integer read fSlotIndex;
public
property RTTIPropsCache[index: integer]: TSMRTTIPropCache read getRTTIPropsCache;
property jsObjName: AnsiString read FjsObjName;
property DeterministicCnt: Cardinal read fDeterministicCnt;
property FirstDeterministicSlotIndex: Cardinal read fFirstDeterministicSlotIndex;
function getMethod(const aJSFunction: PJSFunction; var obj: PJSObject): PSMMethodRec; //overload;
constructor Create(Cx: PJSContext; aRttiCls: TClass; aParent: PJSRootedObject; slotIndex: integer); virtual;
function NewSMInstance(aCx: PJSContext; argc: uintN; var vp: JSArgRec): TObject; virtual;
end;
TSMFastNativeCall = function(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean of object;
function IsInstanceObject(cx: PJSContext; jsobj: PJSObject; var asmInstance: PSMInstanceRecord): boolean; overload;
function IsInstanceObject(cx: PJSContext; jval: jsval; var asmInstance: PSMInstanceRecord): boolean; overload;
function IsProtoObject(cx: PJSContext; jsobj: PJSObject; var asmProto: TSMCustomProtoObject): boolean; overload;
function IsProtoObject(cx: PJSContext; jval: jsval; var asmProto: TSMCustomProtoObject): boolean; overload;
procedure defineEnum(cx: PJSContext; ti: PTypeInfo; aParent: PJSRootedObject);
function defineClass(cx: PJSContext; AForClass: TClass; AProto: TSMCustomProtoObjectClass; aParent: PJSRootedObject): TSMCustomProtoObject; overload;
function defineClass(cx: PJSContext; AForClass: TClass; AProto: TSMCustomProtoObjectClass; aParentProto: TSMCustomProtoObject): TSMCustomProtoObject; overload;
function camelize(const S: AnsiString): AnsiString;
const
SM_NOT_A_NATIVE_OBJECT = 'Not a native object';
function strComparePropGetterSetter(prop_name, jsName: AnsiString; isGetter: boolean): Boolean; {$ifdef HASINLINE}inline;{$endif}
// for can make strComparePropGetterSetter inlined
const prefix: array[boolean] of TShort4 = ('set ','get ');
// called when the interpreter wants to create an object through a new TMyObject ()
function SMCustomObjectConstruct(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean; cdecl;
// called when the interpreter destroys the object
{$IFDEF SM52}
procedure SMCustomObjectDestroy(var fop: JSFreeOp; obj: PJSObject); cdecl;
{$ELSE}
procedure SMCustomObjectDestroy(var rt: PJSRuntime; obj: PJSObject); cdecl;
{$ENDIF}
implementation
function strComparePropGetterSetter(prop_name, jsName: AnsiString; isGetter: boolean): Boolean;
var jsNameLen: integer;
ch1, ch2: PAnsiChar;
begin
jsNameLen := Length(jsName);
Result := (jsNameLen > 0) and (Length(prop_name) = jsNameLen + 4) and
((PInteger(@prop_name[1]))^ = (PInteger(@prefix[isGetter][1]))^);
if Result then begin
ch1 := @jsName[1];
ch2 := @prop_name[5];
while jsNameLen >= 4 do begin
if PInteger(ch1)^ <> PInteger(ch2)^ then begin
result := False;
exit;
end;
inc(ch1, 4);
inc(ch2, 4);
Dec(jsNameLen, 4);
end;
if jsNameLen >= 2 then begin
if PWord(ch1)^ <> PWord(ch2)^ then begin
result := False;
exit;
end;
inc(ch1, 2);
inc(ch2, 2);
Dec(jsNameLen, 2);
end;
if jsNameLen = 1 then begin
if ch1^ <> ch2^ then begin
result := False;
exit;
end;
end;
end;
end;
function camelize(const S: AnsiString): AnsiString;
var
Ch: AnsiChar;
begin
result := '';
if S='' then
exit;
SetString(result, PAnsiChar(S), length(s));
Ch := PAnsiChar(s)^;
case Ch of
'A' .. 'Z':
Ch := AnsiChar(byte(Ch) or $20);
end;
PAnsiChar(Result)^ := Ch;
end;
const
// Magic constant for TSMObjectRecord
SMObjectRecordMagic: Word = 43857;
{$IFDEF SM52}
jsdef_classOpts: JSClassOps = (
finalize: SMCustomObjectDestroy; // call then JS object GC}
construct: SMCustomObjectConstruct
);
jsdef_class: JSClass = (name: '';
flags: uint32(JSCLASS_HAS_PRIVATE);
cOps: @jsdef_classOpts
);
{$ELSE}
jsdef_class: JSClass = (name: '';
flags: uint32(JSCLASS_HAS_PRIVATE);
finalize: SMCustomObjectDestroy; // call then JS object GC}
construct: SMCustomObjectConstruct
);
{$ENDIF}
// create object var obj = new TMyObject();
function SMCustomObjectConstruct(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean; cdecl;
var
jsobj: PJSObject;
Proto: TSMCustomProtoObject;
Inst: PSMInstanceRecord;
begin
Result := false;
try
if not vp.IsConstructing then
raise ESMException.Create('Construct: not JS_IS_CONSTRUCTING');
jsobj := vp.calleObject;
if not IsProtoObject(cx, jsobj, Proto) then
raise ESMException.Create('Construct: no private data');
new(Inst);
vp.rval := Inst.CreateNew(cx, Proto, argc, vp);
Result := true;
except
on E: Exception do
JSError(cx, E);
end;
end;
{$IFDEF SM52}
procedure SMCustomObjectDestroy(var fop: JSFreeOp; obj: PJSObject); cdecl;
{$ELSE}
procedure SMCustomObjectDestroy(var rt: PJSRuntime; obj: PJSObject); cdecl;
{$ENDIF}
var
ObjRec: PSMObjectRecord;
Inst: PSMInstanceRecord;
proto: TSMCustomProtoObject;
begin
ObjRec := obj.PrivateData;
if Assigned(ObjRec) and (ObjRec.IsMagicCorrect) then
begin
if (ObjRec.DataType=otInstance) and Assigned(ObjRec.Data) then begin
Inst := ObjRec.Data;
Inst.freeNative;
Dispose(Inst);
end else if (ObjRec.DataType=otProto) and Assigned(ObjRec.Data) then begin
proto := ObjRec.Data;
FreeAndNil(proto);
end else begin
Dispose(ObjRec.Data); // ObjRec.Data is a PSMIdxPropReader from SyNoideNewProto
end;
Dispose(ObjRec);
obj.PrivateData := nil;
end;
end;
function IsSMObject(cx: PJSContext; jsobj: PJSObject; var aObj: PSMObjectRecord): boolean; overload;
var
P: PSMObjectRecord;
CLS: PJSClass;
begin
Result := false;
CLS := jsobj.Class_;
if CLS.flags and JSCLASS_HAS_PRIVATE = 0 then
Exit;
p := jsobj.PrivateData;
if (p <> nil) then
if (P.IsMagicCorrect) then begin
aObj := p;
Result := true;
end else
raise ESMException.Create('Incorrect IsMagicCorrect');
end;
function IsSMObject(cx: PJSContext; jval: jsval; var aObj: PSMObjectRecord): boolean; overload;
var
obj: PJSObject;
begin
Result := jval.isObject;
if not Result then exit;
obj := jval.asObject;
Result := IsSMObject(cx, obj, aObj);
end;
function IsInstanceObject(cx: PJSContext; jval: jsval; var asmInstance: PSMInstanceRecord): boolean; overload;
var
obj: PJSObject;
begin
Result := jval.isObject;
if not Result then exit;
obj := jval.asObject;
Result := IsInstanceObject(cx, obj, asmInstance);
end;
function IsInstanceObject(cx: PJSContext; jsobj: PJSObject; var asmInstance: PSMInstanceRecord): boolean;
var
aObj: PSMObjectRecord;
begin
Result := IsSMObject(cx, jsobj, aObj);
if Result then
Result := (aObj.DataType = otInstance);
if not Result then
asmInstance := nil
else
asmInstance := aObj.Data;
end;
function IsProtoObject(cx: PJSContext; jsobj: PJSObject; var asmProto: TSMCustomProtoObject): boolean;
var
aObj: PSMObjectRecord;
begin
Result := IsSMObject(cx, jsobj, aObj);
if Result then
Result := (aObj.DataType = otProto);
if not Result then
asmProto := nil
else
asmProto := aObj.Data;
end;
function IsProtoObject(cx: PJSContext; jval: jsval; var asmProto: TSMCustomProtoObject): boolean;
var
obj: PJSObject;
begin
Result := jval.isObject;
if not Result then exit;
obj := jval.asObject;
Result := Assigned(obj) and IsProtoObject(cx, obj, asmProto);
end;
procedure defineEnum(cx: PJSContext; ti: PTypeInfo; aParent: PJSRootedObject);
var
i: integer;
s: SynUnicode;
found: Boolean;
val: jsval;
obj_: PJSRootedObject;
begin
if (ti^.Name = 'Boolean') then
Exit;
s := UTF8ToSynUnicode(ShortStringToUTF8(ti^.Name));
if (aParent.ptr.HasUCProperty(cx, Pointer(s), Length(s), found)) and found then
exit; //enum already defined
obj_ := cx.NewRootedObject(cx.NewObject(nil));
try
aParent.ptr.DefineUCProperty(cx, Pointer(s), Length(s), obj_.ptr.ToJSValue, JSPROP_ENUMERATE or JSPROP_PERMANENT, nil, nil);
with ti^.EnumBaseType^ do begin
for i := MinValue to MaxValue do begin
s := UTF8ToSynUnicode(GetEnumNameTrimed(i));
val.asInteger := i;
obj_.ptr.DefineUCProperty(cx, Pointer(s), Length(s), val, JSPROP_ENUMERATE or JSPROP_PERMANENT, nil, nil);
end;
end;
finally
cx.FreeRootedObject(obj_);
end;
//TODO freez (seal) created JS object to not allow it modification
end;
function defineClass(cx: PJSContext; AForClass: TClass; AProto: TSMCustomProtoObjectClass; aParent: PJSRootedObject): TSMCustomProtoObject;
var
global: PJSObject;
i: integer;
val: jsval;
begin
global := cx.CurrentGlobalOrNull;
for I := JSCLASS_GLOBAL_SLOT_COUNT to 255 do begin
val := global.ReservedSlot[i];
if val.isVoid then begin
//create new
result := AProto.Create(Cx, AForClass, aParent, i);
exit;
end else if IsProtoObject(cx, val, Result) then begin
if Result.fRttiCls = AForClass then
exit; // The class prototype has already created
end else if val.isString then begin
if val.asJSString.ToString(cx) = AForClass.ClassName then
exit; // The class prototype is being created right now
end else
raise ESMException.Create('Slot value is not ProtoObject');
end;
raise Exception.Create('defineClass Error: many proto' + AForClass.ClassName);
end;
function defineClass(cx: PJSContext; AForClass: TClass; AProto: TSMCustomProtoObjectClass; aParentProto: TSMCustomProtoObject): TSMCustomProtoObject; overload;
var
global: PJSObject;
i: integer;
val: jsval;
aParent: PJSRootedObject;
begin
global := cx.CurrentGlobalOrNull;
for I := JSCLASS_GLOBAL_SLOT_COUNT to 255 do begin
val := global.ReservedSlot[i];
if val.isVoid then begin
//create new
aParent := cx.NewRootedObject(global.ReservedSlot[aParentProto.fSlotIndex].asObject.ReservedSlot[aParentProto.FirstDeterministicSlotIndex].asObject);
try
result := AProto.Create(Cx, AForClass, aParent, i);
finally
cx.FreeRootedObject(aParent);
end;
exit;
end else begin
if IsProtoObject(cx, val, Result) then begin
if Result.fRttiCls = AForClass then
exit;
end else
raise ESMException.Create('Slot value is not ProtoObject');
end;
end;
raise Exception.Create('defineClass Error: many proto' + AForClass.ClassName);
end;
{ TSMObjectRecord }
procedure TSMObjectRecord.init(aDataType: TSMObjectType; aData: Pointer);
begin
Self.Magic := SMObjectRecordMagic;
Self.DataType := aDataType;
Self.Data := aData;
end;
function TSMObjectRecord.IsMagicCorrect: boolean;
begin
Result := Magic = SMObjectRecordMagic;
end;
{ TSMInstanceRecord }
function TSMInstanceRecord.CreateForObj(acx: PJSContext; AInstance: TObject; AProto: TSMCustomProtoObjectClass; aParent: PJSRootedObject): jsval;
begin
Result := InternalCreate(acx, AInstance, defineClass(acx, AInstance.ClassType, AProto, aParent));
OwnInstance := false;
end;
function TSMInstanceRecord.CreateForObj(acx: PJSContext; AInstance: TObject;
AProto: TSMCustomProtoObjectClass;
aParentProto: TSMCustomProtoObject): jsval;
begin
Result := InternalCreate(acx, AInstance, defineClass(acx, AInstance.ClassType, AProto, aParentProto));
OwnInstance := false;
end;
function TSMInstanceRecord.CreateNew(acx: PJSContext; AProto: TSMCustomProtoObject; argc: uintN;
var vp: JSArgRec): jsval;
begin
result := InternalCreate(aCx, AProto.NewSMInstance(acx, argc, vp), AProto );
OwnInstance := True;
end;
procedure TSMInstanceRecord.freeNative;
begin
if Assigned(onFree) then
onFree(@Self);
if OwnInstance then begin
if Assigned(instance) then
FreeAndNil(instance);
end;
Instance := nil; // in case the FInstance is IUnknown
end;
function TSMInstanceRecord.InternalCreate(cx: PJSContext; AInstance: TObject; AProto: TSMCustomProtoObject): jsval;
var
ObjRec: PSMObjectRecord;
jsobj: PJSRootedObject;
global: PJSRootedObject;
protoObj: PJSRootedObject;
begin
proto := AProto;
onFree := nil;
AddData := nil;
cx.BeginRequest;
try
global := cx.NewRootedObject(cx.CurrentGlobalOrNull);
protoObj := cx.NewRootedObject(global.ptr.ReservedSlot[proto.fSlotIndex].asObject);
jsobj := cx.NewRootedObject(cx.NewObjectWithGivenProto(@proto.FJSClass, protoObj.ptr));
try
// premature optimization is the root of evil
// as shown by valgrind profiler better to not redefine props in object
// but let's JS engine to use it from prototype
//if Length(AProto.FJSProps)>0 then
// jsobj.ptr.DefineProperties(cx,@AProto.FJSProps[0]);
Instance := AInstance;
new(ObjRec);
ObjRec.init(otInstance, @Self);
jsobj.ptr.PrivateData := ObjRec;
result := jsobj.ptr.ToJSValue;
finally
cx.FreeRootedObject(jsobj);
cx.FreeRootedObject(protoObj);
cx.FreeRootedObject(global);
end;
finally
cx.EndRequest;
end;
end;
{ TSMCustomProtoObject }
constructor TSMCustomProtoObject.Create(Cx: PJSContext; aRttiCls: TClass; aParent: PJSRootedObject; slotIndex: integer);
var
i: Cardinal;
ObjRec: PSMObjectRecord;
obj: PJSObject;
global: PJSObject;
begin
fRttiCls := aRttiCls;
fCx := Cx;
fSlotIndex := slotIndex;
FjsObjName := StringToAnsi7(fRttiCls.ClassName);
global := cx.CurrentGlobalOrNull;
global.ReservedSlot[fSlotIndex] := cx.NewJSString(fRttiCls.ClassName).ToJSVal;
FMethodsDA.Init(TypeInfo(TSMMethodDynArray), FMethods);
InitObject(aParent);
FJSClass := GetJSClass;
FJSClass.Name := PCChar(FjsObjName);
fFirstDeterministicSlotIndex := (FJSClass.flags and (JSCLASS_RESERVED_SLOTS_MASK shl JSCLASS_RESERVED_SLOTS_SHIFT))
shr JSCLASS_RESERVED_SLOTS_SHIFT;
if fFirstDeterministicSlotIndex + fDeterministicCnt >255 then
raise ESMException.Create('Too many properties');
if fFirstDeterministicSlotIndex + uint32(FMethodsDA.Count) + 1 >255 then
raise ESMException.Create('Too many methods');
FJSClass.flags := FJSClass.flags and not (JSCLASS_RESERVED_SLOTS_MASK shl JSCLASS_RESERVED_SLOTS_SHIFT) or
((fFirstDeterministicSlotIndex + fDeterministicCnt) shl JSCLASS_RESERVED_SLOTS_SHIFT);
FJSClassProto := FJSClass;
FJSClassProto.flags := FJSClassProto.flags and not (JSCLASS_RESERVED_SLOTS_MASK shl JSCLASS_RESERVED_SLOTS_SHIFT) or
((fFirstDeterministicSlotIndex + uint32(FMethodsDA.Count) + 1) shl JSCLASS_RESERVED_SLOTS_SHIFT);
cx.BeginRequest;
try
//TODO prototypes chain fjsproto
if length(FJSProps) = 0 then begin
obj := aParent.ptr.InitClass(cx ,nullObj , @FJSClassProto, nil, 0, nil , nil, nil, nil);
end else begin
SetLength(FJSProps, Length(FJSProps) + 1); // must be null terminate!!
obj := aParent.ptr.InitClass(cx ,nullObj , @FJSClassProto, nil, 0, @FJSProps[0] , nil, nil, nil);
end;
obj.ReservedSlot[fFirstDeterministicSlotIndex] := aParent.ptr.ToJSValue;
//define JS methods
if FMethodsDA.Count > 0 then
for i := 0 to FMethodsDA.Count-1 do with FMethods[i] do begin
obj.ReservedSlot[fFirstDeterministicSlotIndex + i + 1] :=
obj.DefineUCFunction(cx, PCChar16(ujsName),
Length(ujsName), call, nargs, uint32(flags)).ToJSValue;
end;
new(ObjRec);
ObjRec.init(otProto,self);
obj.PrivateData := ObjRec;
global.ReservedSlot[fSlotIndex] := obj.ToJSValue;
finally
cx.EndRequest;
end;
end;
function CustomProtoObject_freeNative(cx: PJSContext; argc: uintN; var vp: JSArgRec): Boolean; cdecl;
var
nativeObj: PSMInstanceRecord;
begin
Result := false;
try
if not IsInstanceObject(cx, vp.this[cx], nativeObj) then
raise ESMException.Create('Object not Native');
nativeObj.FreeNative;
Result := true;
except
on E: Exception do
begin
JSError(cx, E);
end;
end;
end;
procedure TSMCustomProtoObject.definePrototypeMethod(const ajsName: SynUnicode; const aCall: JSNative; aNargs: uintN; aFlags: TJSPropertyAttrs);
var idx: integer;
added: boolean;
begin
idx := FMethodsDA.FindHashedForAdding(ajsName, added);
if added then begin
with FMethods[idx] do begin
ujsName := ajsName;
nargs := aNargs;
call := aCall;
flags := aFlags;
end;
end else
raise ESMException.CreateUtf8('Duplicated native function %()',[ajsName]);
end;
function TSMCustomProtoObject.getMethod(const aJSFunction: PJSFunction; var obj: PJSObject): PSMMethodRec;
var
i: Cardinal;
begin
result := nil;
if FMethodsDA.Count > 0 then
for i := 0 to FMethodsDA.Count-1 do
if obj.ReservedSlot[i+1+fFirstDeterministicSlotIndex].asObject = aJSFunction then begin
Result := @FMethods[i];
break;
end;
end;
function TSMCustomProtoObject.NewSMInstance(aCx: PJSContext; argc: uintN;
var vp: JSArgRec): TObject;
var
ItemInstance: TClassInstance;
begin
ItemInstance.Init(fRttiCls);
result := ItemInstance.CreateNew;
end;
function TSMCustomProtoObject.getRTTIPropsCache(index: integer): TSMRTTIPropCache;
begin
Result := fRTTIPropsCache[index];
end;
function TSMCustomProtoObject.GetJSClass: JSClass;
begin
Result := jsdef_class; // default values
end;
procedure TSMCustomProtoObject.InitObject(aParent: PJSRootedObject);
begin
definePrototypeMethod('freeNative', @CustomProtoObject_freeNative, 0, [jspEnumerate, jspPermanent, jspReadOnly]);
end;
end.