2 // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 namespace Boo
.Lang
.Compiler
.Steps
31 using System
.Diagnostics
;
32 using Boo
.Lang
.Compiler
.Ast
;
33 using Boo
.Lang
.Compiler
.TypeSystem
;
35 public class ImplementICallableOnCallableDefinitions
: AbstractVisitorCompilerStep
37 override public void Run()
42 override public void OnModule(Module node
)
44 Visit(node
.Members
, NodeType
.ClassDefinition
);
47 override public void OnClassDefinition(ClassDefinition node
)
49 Visit(node
.Members
, NodeType
.ClassDefinition
);
51 InternalCallableType type
= node
.Entity
as InternalCallableType
;
54 ImplementICallableCall(type
, node
);
58 int GetByRefParamCount(CallableSignature signature
)
61 foreach (IParameter param
in signature
.Parameters
)
63 if (param
.IsByRef
) ++count
;
68 void ImplementICallableCall(InternalCallableType type
, ClassDefinition node
)
70 Method call
= (Method
)node
.Members
["Call"];
71 Debug
.Assert(null != call
);
72 Debug
.Assert(0 == call
.Body
.Statements
.Count
);
74 CallableSignature signature
= type
.GetSignature();
75 int byRefCount
= GetByRefParamCount(signature
);
78 ImplementByRefICallableCall(call
, type
, node
, signature
, byRefCount
);
82 ImplementRegularICallableCall(call
, type
, node
, signature
);
86 void ImplementByRefICallableCall(
88 InternalCallableType type
,
90 CallableSignature signature
,
93 MethodInvocationExpression mie
= CreateInvokeInvocation(type
);
94 IParameter
[] parameters
= signature
.Parameters
;
95 ReferenceExpression args
= CodeBuilder
.CreateReference(call
.Parameters
[0]);
96 InternalLocal
[] temporaries
= new InternalLocal
[byRefCount
];
99 for (int i
=0; i
<parameters
.Length
; ++i
)
101 SlicingExpression slice
= CodeBuilder
.CreateSlicing(args
.CloneNode(), i
);
103 IParameter parameter
= parameters
[i
];
104 if (parameter
.IsByRef
)
106 IType tempType
= parameter
.Type
;
107 if (tempType
.IsByRef
)
109 tempType
= tempType
.GetElementType();
111 temporaries
[byRefIndex
] = CodeBuilder
.DeclareLocal(call
,
112 "__temp_" + parameter
.Name
,
116 CodeBuilder
.CreateAssignment(
117 CodeBuilder
.CreateReference(temporaries
[byRefIndex
]),
118 CodeBuilder
.CreateCast(
123 CodeBuilder
.CreateReference(
124 temporaries
[byRefIndex
]));
130 mie
.Arguments
.Add(slice
);
134 if (TypeSystemServices
.VoidType
== signature
.ReturnType
)
137 PropagateByRefParameterChanges(call
, parameters
, temporaries
);
141 InternalLocal invokeReturnValue
= CodeBuilder
.DeclareLocal(call
,
142 "__returnValue", signature
.ReturnType
);
144 CodeBuilder
.CreateAssignment(
145 CodeBuilder
.CreateReference(invokeReturnValue
),
147 PropagateByRefParameterChanges(call
, parameters
, temporaries
);
150 CodeBuilder
.CreateReference(invokeReturnValue
)));
154 void PropagateByRefParameterChanges(Method call
, IParameter
[] parameters
, InternalLocal
[] temporaries
)
157 for (int i
=0; i
<parameters
.Length
; ++i
)
159 if (!parameters
[i
].IsByRef
) continue;
161 SlicingExpression slice
= CodeBuilder
.CreateSlicing(
162 CodeBuilder
.CreateReference(call
.Parameters
[0]),
165 CodeBuilder
.CreateAssignment(
167 CodeBuilder
.CreateReference(temporaries
[byRefIndex
])));
172 void ImplementRegularICallableCall(
174 InternalCallableType type
,
175 ClassDefinition node
,
176 CallableSignature signature
)
178 MethodInvocationExpression mie
= CreateInvokeInvocation(type
);
179 IParameter
[] parameters
= signature
.Parameters
;
180 int fixedParametersLength
= signature
.AcceptVarArgs
? parameters
.Length
- 1 : parameters
.Length
;
181 for (int i
=0; i
<fixedParametersLength
; ++i
)
183 SlicingExpression slice
= CodeBuilder
.CreateSlicing(
184 CodeBuilder
.CreateReference(call
.Parameters
[0]),
186 mie
.Arguments
.Add(slice
);
189 if (signature
.AcceptVarArgs
)
191 if (parameters
.Length
== 1)
193 mie
.Arguments
.Add(CodeBuilder
.CreateReference(call
.Parameters
[0]));
198 CodeBuilder
.CreateMethodInvocation(
199 RuntimeServices_GetRange1
,
200 CodeBuilder
.CreateReference(call
.Parameters
[0]),
201 CodeBuilder
.CreateIntegerLiteral(fixedParametersLength
)));
205 if (TypeSystemServices
.VoidType
== signature
.ReturnType
)
211 call
.Body
.Add(new ReturnStatement(mie
));
215 MethodInvocationExpression
CreateInvokeInvocation(InternalCallableType type
)
217 return CodeBuilder
.CreateMethodInvocation(
218 CodeBuilder
.CreateSelfReference(type
),
219 type
.GetInvokeMethod());
222 IMethod _RuntimeServices_GetRange1
;
224 IMethod RuntimeServices_GetRange1
228 if (null == _RuntimeServices_GetRange1
)
230 _RuntimeServices_GetRange1
= NameResolutionService
.ResolveMethod(TypeSystemServices
.RuntimeServicesType
, "GetRange1");
232 return _RuntimeServices_GetRange1
;