mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-14 09:09:19 +02:00
pastojs: specializations: create initSpec for class/record only if typeinfo or global field exists
git-svn-id: trunk@46772 -
This commit is contained in:
parent
965f759c0d
commit
c45e56bc91
@ -1516,7 +1516,7 @@ type
|
|||||||
override;
|
override;
|
||||||
procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem);
|
procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem);
|
||||||
override;
|
override;
|
||||||
function SpecializeNeedsDelay(SpecializedItem: TPRSpecializedItem): TPasElement; virtual;
|
function SpecializeParamsNeedDelay(SpecializedItem: TPRSpecializedItem): TPasElement; virtual;
|
||||||
function CreateLongName(SpecializedItem: TPRSpecializedItem): string; virtual;
|
function CreateLongName(SpecializedItem: TPRSpecializedItem): string; virtual;
|
||||||
protected
|
protected
|
||||||
const
|
const
|
||||||
@ -1909,6 +1909,7 @@ type
|
|||||||
Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
|
Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
|
||||||
Function GetImplJSProcScope(El: TPasElement; Src: TJSSourceElements;
|
Function GetImplJSProcScope(El: TPasElement; Src: TJSSourceElements;
|
||||||
AContext: TConvertContext): TPas2JSProcedureScope;
|
AContext: TConvertContext): TPas2JSProcedureScope;
|
||||||
|
Function SpecializeNeedsDelay(El: TPasGenericType; AContext: TConvertContext): boolean; virtual;
|
||||||
// Never create an element manually, always use the below functions
|
// Never create an element manually, always use the below functions
|
||||||
Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
|
Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
|
||||||
Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
|
Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
|
||||||
@ -5027,7 +5028,7 @@ begin
|
|||||||
|
|
||||||
El:=SpecializedItem.SpecializedEl;
|
El:=SpecializedItem.SpecializedEl;
|
||||||
if (El is TPasGenericType)
|
if (El is TPasGenericType)
|
||||||
and (SpecializeNeedsDelay(SpecializedItem)<>nil) then
|
and (SpecializeParamsNeedDelay(SpecializedItem)<>nil) then
|
||||||
TPas2JSResolverHub(Hub).AddJSDelaySpecialize(TPasGenericType(El));
|
TPas2JSResolverHub(Hub).AddJSDelaySpecialize(TPasGenericType(El));
|
||||||
|
|
||||||
if El is TPasMembersType then
|
if El is TPasMembersType then
|
||||||
@ -5044,7 +5045,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TPas2JSResolver.SpecializeNeedsDelay(
|
function TPas2JSResolver.SpecializeParamsNeedDelay(
|
||||||
SpecializedItem: TPRSpecializedItem): TPasElement;
|
SpecializedItem: TPRSpecializedItem): TPasElement;
|
||||||
// finds first specialize param defined later than the generic
|
// finds first specialize param defined later than the generic
|
||||||
// For example: generic in the unit interface, param in implementation
|
// For example: generic in the unit interface, param in implementation
|
||||||
@ -14729,7 +14730,7 @@ var
|
|||||||
C: TClass;
|
C: TClass;
|
||||||
AssignSt: TJSSimpleAssignStatement;
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt,
|
NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt,
|
||||||
SpecializeNeedsDelay: Boolean;
|
SpecializeDelay: Boolean;
|
||||||
Proc: TPasProcedure;
|
Proc: TPasProcedure;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
@ -14760,14 +14761,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
FreeAndNil(Scope.MsgIntToProc);
|
FreeAndNil(Scope.MsgIntToProc);
|
||||||
FreeAndNil(Scope.MsgStrToProc);
|
FreeAndNil(Scope.MsgStrToProc);
|
||||||
SpecializeNeedsDelay:=aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil;
|
SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
Scope:=nil;
|
Scope:=nil;
|
||||||
IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
|
IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
|
||||||
Ancestor:=El.AncestorType;
|
Ancestor:=El.AncestorType;
|
||||||
SpecializeNeedsDelay:=false;
|
SpecializeDelay:=false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// create call 'rtl.createClass(' or 'rtl.createInterface('
|
// create call 'rtl.createClass(' or 'rtl.createInterface('
|
||||||
@ -14874,7 +14875,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// add class members: types and class vars
|
// add class members: types and class vars
|
||||||
if SpecializeNeedsDelay then
|
if SpecializeDelay then
|
||||||
DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
|
DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
|
||||||
if El.ObjKind in ([okClass]+okAllHelpers) then
|
if El.ObjKind in ([okClass]+okAllHelpers) then
|
||||||
begin
|
begin
|
||||||
@ -14912,7 +14913,7 @@ begin
|
|||||||
RaiseNotSupported(P,FuncContext,20161221233338);
|
RaiseNotSupported(P,FuncContext,20161221233338);
|
||||||
if NewEl<>nil then
|
if NewEl<>nil then
|
||||||
begin
|
begin
|
||||||
if SpecializeNeedsDelay and not (P is TPasProcedure) then
|
if SpecializeDelay and not (P is TPasProcedure) then
|
||||||
AddToSourceElements(DelaySrc,NewEl)
|
AddToSourceElements(DelaySrc,NewEl)
|
||||||
else
|
else
|
||||||
AddToSourceElements(Src,NewEl);
|
AddToSourceElements(Src,NewEl);
|
||||||
@ -14980,7 +14981,7 @@ begin
|
|||||||
AddClassMessageIds(El,Src,FuncContext,pbivnMessageInt);
|
AddClassMessageIds(El,Src,FuncContext,pbivnMessageInt);
|
||||||
AddClassMessageIds(El,Src,FuncContext,pbivnMessageStr);
|
AddClassMessageIds(El,Src,FuncContext,pbivnMessageStr);
|
||||||
// add RTTI init function
|
// add RTTI init function
|
||||||
if SpecializeNeedsDelay then
|
if SpecializeDelay then
|
||||||
AddClassRTTI(El,DelaySrc,DelayFuncContext)
|
AddClassRTTI(El,DelaySrc,DelayFuncContext)
|
||||||
else
|
else
|
||||||
AddClassRTTI(El,Src,FuncContext);
|
AddClassRTTI(El,Src,FuncContext);
|
||||||
@ -15478,7 +15479,7 @@ var
|
|||||||
Prop: TJSObjectLiteralElement;
|
Prop: TJSObjectLiteralElement;
|
||||||
aResolver: TPas2JSResolver;
|
aResolver: TPas2JSResolver;
|
||||||
Scope: TPas2JSProcTypeScope;
|
Scope: TPas2JSProcTypeScope;
|
||||||
SpecializeNeedsDelay: Boolean;
|
SpecializeDelay: Boolean;
|
||||||
FuncSt: TJSFunctionDeclarationStatement;
|
FuncSt: TJSFunctionDeclarationStatement;
|
||||||
AssignSt: TJSSimpleAssignStatement;
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
begin
|
begin
|
||||||
@ -15498,8 +15499,7 @@ begin
|
|||||||
RaiseNotSupported(El,AContext,20181231112029);
|
RaiseNotSupported(El,AContext,20181231112029);
|
||||||
|
|
||||||
Scope:=El.CustomData as TPas2JSProcTypeScope;
|
Scope:=El.CustomData as TPas2JSProcTypeScope;
|
||||||
SpecializeNeedsDelay:=(Scope<>nil)
|
SpecializeDelay:=(Scope<>nil) and SpecializeNeedsDelay(El,AContext);
|
||||||
and (aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil);
|
|
||||||
|
|
||||||
// module.$rtti.$ProcVar("name",function(){})
|
// module.$rtti.$ProcVar("name",function(){})
|
||||||
if El.IsReferenceTo then
|
if El.IsReferenceTo then
|
||||||
@ -15514,7 +15514,7 @@ begin
|
|||||||
Prop:=Obj.Elements.AddElement;
|
Prop:=Obj.Elements.AddElement;
|
||||||
InnerCall:=CreateCallExpression(El);
|
InnerCall:=CreateCallExpression(El);
|
||||||
|
|
||||||
if SpecializeNeedsDelay then
|
if SpecializeDelay then
|
||||||
begin
|
begin
|
||||||
Prop.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
|
Prop.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
|
||||||
// init: function(){ this.procsig = rtl.newTIProcSignature(...) }
|
// init: function(){ this.procsig = rtl.newTIProcSignature(...) }
|
||||||
@ -15610,7 +15610,7 @@ var
|
|||||||
var
|
var
|
||||||
aResolver: TPas2JSResolver;
|
aResolver: TPas2JSResolver;
|
||||||
Scope: TPas2JSArrayScope;
|
Scope: TPas2JSArrayScope;
|
||||||
SpecializeNeedsDelay: Boolean;
|
SpecializeDelay: Boolean;
|
||||||
AssignSt: TJSSimpleAssignStatement;
|
AssignSt: TJSSimpleAssignStatement;
|
||||||
CallName, ArrName: String;
|
CallName, ArrName: String;
|
||||||
Obj: TJSObjectLiteral;
|
Obj: TJSObjectLiteral;
|
||||||
@ -15644,8 +15644,7 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
Scope:=El.CustomData as TPas2JSArrayScope;
|
Scope:=El.CustomData as TPas2JSArrayScope;
|
||||||
SpecializeNeedsDelay:=(Scope<>nil)
|
SpecializeDelay:=(Scope<>nil) and (SpecializeNeedsDelay(El,AContext));
|
||||||
and (aResolver.SpecializeNeedsDelay(Scope.SpecializedFromItem)<>nil);
|
|
||||||
|
|
||||||
ProcScope:=nil;
|
ProcScope:=nil;
|
||||||
Src:=nil;
|
Src:=nil;
|
||||||
@ -15793,7 +15792,7 @@ begin
|
|||||||
until false;
|
until false;
|
||||||
end;
|
end;
|
||||||
// eltype: ref
|
// eltype: ref
|
||||||
if not SpecializeNeedsDelay then
|
if not SpecializeDelay then
|
||||||
begin
|
begin
|
||||||
Prop:=Obj.Elements.AddElement;
|
Prop:=Obj.Elements.AddElement;
|
||||||
Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
|
Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
|
||||||
@ -16823,6 +16822,7 @@ var
|
|||||||
aResolver: TPas2JSResolver;
|
aResolver: TPas2JSResolver;
|
||||||
begin
|
begin
|
||||||
if not IsElementUsed(El) then exit;
|
if not IsElementUsed(El) then exit;
|
||||||
|
if not SpecializeNeedsDelay(El,AContext) then exit;
|
||||||
C:=El.ClassType;
|
C:=El.ClassType;
|
||||||
if (C=TPasRecordType)
|
if (C=TPasRecordType)
|
||||||
or (C=TPasClassType) then
|
or (C=TPasClassType) then
|
||||||
@ -22495,6 +22495,84 @@ begin
|
|||||||
Result:=AContext.Resolver.GetTopLvlProcScope(El);
|
Result:=AContext.Resolver.GetTopLvlProcScope(El);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TPasToJSConverter.SpecializeNeedsDelay(El: TPasGenericType;
|
||||||
|
AContext: TConvertContext): boolean;
|
||||||
|
var
|
||||||
|
SpecItem: TPRSpecializedItem;
|
||||||
|
C: TClass;
|
||||||
|
Members: TFPList;
|
||||||
|
ChildEl: TPasElement;
|
||||||
|
PasVar: TPasVariable;
|
||||||
|
aResolver: TPas2JSResolver;
|
||||||
|
PasVarType: TPasType;
|
||||||
|
IsRecord, NeedInitFunction: Boolean;
|
||||||
|
aClass: TPasClassType;
|
||||||
|
ClassScope: TPas2JSClassScope;
|
||||||
|
IntfKind: String;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
aResolver:=AContext.Resolver;
|
||||||
|
if aResolver=nil then exit;
|
||||||
|
if not (El.CustomData is TPasGenericScope) then exit;
|
||||||
|
SpecItem:=TPasGenericScope(El.CustomData).SpecializedFromItem;
|
||||||
|
if aResolver.SpecializeParamsNeedDelay(SpecItem)=nil then
|
||||||
|
exit; // params are declared in front of generic -> no need to delay
|
||||||
|
|
||||||
|
if HasTypeInfo(El,AContext) then
|
||||||
|
exit(true); // RTTI -> delay needed
|
||||||
|
|
||||||
|
C:=El.ClassType;
|
||||||
|
if El.InheritsFrom(TPasMembersType) then
|
||||||
|
begin
|
||||||
|
IsRecord:=C=TPasRecordType;
|
||||||
|
|
||||||
|
if C=TPasClassType then
|
||||||
|
begin
|
||||||
|
aClass:=TPasClassType(El);
|
||||||
|
ClassScope:=TPas2JSClassScope(El.CustomData);
|
||||||
|
if aClass.ObjKind=okInterface then
|
||||||
|
begin
|
||||||
|
IntfKind:='';
|
||||||
|
if (ClassScope.AncestorScope=nil) and (not (coNoTypeInfo in Options)) then
|
||||||
|
case aClass.InterfaceType of
|
||||||
|
citCom: IntfKind:='com';
|
||||||
|
citCorba: ; // default
|
||||||
|
else
|
||||||
|
RaiseNotSupported(El,AContext,20200905132130);
|
||||||
|
end;
|
||||||
|
NeedInitFunction:=(pcsfPublished in ClassScope.Flags) or (IntfKind<>'');
|
||||||
|
if not NeedInitFunction then
|
||||||
|
exit; // interface without init function -> no need to delay
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Members:=TPasMembersType(El).Members;
|
||||||
|
for i:=0 to Members.Count-1 do
|
||||||
|
begin
|
||||||
|
ChildEl:=TPasElement(Members[i]);
|
||||||
|
if not IsElementUsed(ChildEl) then continue;
|
||||||
|
if ChildEl is TPasVariable then
|
||||||
|
begin
|
||||||
|
PasVar:=TPasVariable(ChildEl);
|
||||||
|
if ChildEl.ClassType=TPasConst then
|
||||||
|
else if ChildEl.ClassType=TPasVariable then
|
||||||
|
begin
|
||||||
|
if (not IsRecord) and (PasVar.VarModifiers*[vmClass, vmStatic]=[]) then
|
||||||
|
continue; // class field -> no delay needed
|
||||||
|
end
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
PasVarType:=aResolver.ResolveAliasType(PasVar.VarType);
|
||||||
|
if (PasVarType.ClassType=TPasRecordType) then
|
||||||
|
exit(true) // global record -> needs delay (Eventually: check if it uses one of the after params)
|
||||||
|
else if (PasVarType.ClassType=TPasArrayType) and (length(TPasArrayType(PasVarType).Ranges)>0) then
|
||||||
|
exit(true); // global static array -> needs delay (Eventually: check if it uses one of the after params)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
|
function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
|
||||||
var
|
var
|
||||||
unary: TJSUnary;
|
unary: TJSUnary;
|
||||||
@ -24986,7 +25064,6 @@ function TPasToJSConverter.ConvertRecordType(El: TPasRecordType;
|
|||||||
AContext: TConvertContext): TJSElement;
|
AContext: TConvertContext): TJSElement;
|
||||||
var
|
var
|
||||||
aResolver: TPas2JSResolver;
|
aResolver: TPas2JSResolver;
|
||||||
RecScope: TPas2JSRecordScope;
|
|
||||||
DelaySrc: TJSSourceElements;
|
DelaySrc: TJSSourceElements;
|
||||||
DelayFuncContext: TFunctionContext;
|
DelayFuncContext: TFunctionContext;
|
||||||
Call: TJSCallExpression;
|
Call: TJSCallExpression;
|
||||||
@ -25001,7 +25078,7 @@ var
|
|||||||
PasVar: TPasVariable;
|
PasVar: TPasVariable;
|
||||||
PasVarType: TPasType;
|
PasVarType: TPasType;
|
||||||
NewFields, Vars, Methods: TFPList;
|
NewFields, Vars, Methods: TFPList;
|
||||||
ok, IsComplex, SpecializeNeedsDelay: Boolean;
|
ok, IsComplex, SpecializeDelay: Boolean;
|
||||||
VarSt: TJSVariableStatement;
|
VarSt: TJSVariableStatement;
|
||||||
begin
|
begin
|
||||||
Result:=nil;
|
Result:=nil;
|
||||||
@ -25020,8 +25097,7 @@ begin
|
|||||||
DelayFuncContext:=nil;
|
DelayFuncContext:=nil;
|
||||||
ok:=false;
|
ok:=false;
|
||||||
try
|
try
|
||||||
RecScope:=TPas2JSRecordScope(El.CustomData);
|
SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
|
||||||
SpecializeNeedsDelay:=aResolver.SpecializeNeedsDelay(RecScope.SpecializedFromItem)<>nil;
|
|
||||||
|
|
||||||
// rtl.recNewT()
|
// rtl.recNewT()
|
||||||
Call:=CreateCallExpression(El);
|
Call:=CreateCallExpression(El);
|
||||||
@ -25076,7 +25152,7 @@ begin
|
|||||||
Vars:=TFPList.Create;
|
Vars:=TFPList.Create;
|
||||||
Methods:=TFPList.Create;
|
Methods:=TFPList.Create;
|
||||||
IsComplex:=false;
|
IsComplex:=false;
|
||||||
if SpecializeNeedsDelay then
|
if SpecializeDelay then
|
||||||
DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
|
DelayFuncContext:=CreateDelayedInitFunction(El,Src,FuncContext,DelaySrc);
|
||||||
for i:=0 to El.Members.Count-1 do
|
for i:=0 to El.Members.Count-1 do
|
||||||
begin
|
begin
|
||||||
@ -25088,7 +25164,7 @@ begin
|
|||||||
if C=TPasVariable then
|
if C=TPasVariable then
|
||||||
begin
|
begin
|
||||||
PasVar:=TPasVariable(P);
|
PasVar:=TPasVariable(P);
|
||||||
if ClassVarModifiersType*PasVar.VarModifiers*[vmClass, vmStatic]<>[] then
|
if PasVar.VarModifiers*[vmClass, vmStatic]<>[] then
|
||||||
IsComplex:=true
|
IsComplex:=true
|
||||||
else if aResolver<>nil then
|
else if aResolver<>nil then
|
||||||
begin
|
begin
|
||||||
@ -25151,7 +25227,7 @@ begin
|
|||||||
RaiseNotSupported(P,FuncContext,20190105105436);
|
RaiseNotSupported(P,FuncContext,20190105105436);
|
||||||
if NewEl<>nil then
|
if NewEl<>nil then
|
||||||
begin
|
begin
|
||||||
if SpecializeNeedsDelay and not (P is TPasProcedure) then
|
if SpecializeDelay and not (P is TPasProcedure) then
|
||||||
AddToSourceElements(DelaySrc,NewEl)
|
AddToSourceElements(DelaySrc,NewEl)
|
||||||
else
|
else
|
||||||
AddToSourceElements(Src,NewEl);
|
AddToSourceElements(Src,NewEl);
|
||||||
@ -25178,7 +25254,7 @@ begin
|
|||||||
// add RTTI init function
|
// add RTTI init function
|
||||||
if (aResolver<>nil) and HasTypeInfo(El,FuncContext) then
|
if (aResolver<>nil) and HasTypeInfo(El,FuncContext) then
|
||||||
begin
|
begin
|
||||||
if SpecializeNeedsDelay then
|
if SpecializeDelay then
|
||||||
CreateRecordRTTI(El,DelaySrc,DelayFuncContext)
|
CreateRecordRTTI(El,DelaySrc,DelayFuncContext)
|
||||||
else
|
else
|
||||||
CreateRecordRTTI(El,Src,FuncContext);
|
CreateRecordRTTI(El,Src,FuncContext);
|
||||||
|
Loading…
Reference in New Issue
Block a user