Line data Source code
1 : /* valaccodememberaccessmodule.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Lesser General Public
8 : * License as published by the Free Software Foundation; either
9 : * version 2.1 of the License, or (at your option) any later version.
10 :
11 : * This library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 :
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this library; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 2930 : public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
26 152037 : public override void visit_member_access (MemberAccess expr) {
27 76042 : CCodeExpression pub_inst = null;
28 :
29 76042 : if (expr.inner != null) {
30 49434 : pub_inst = get_cvalue (expr.inner);
31 : }
32 :
33 184236 : var array_type = expr.value_type as ArrayType;
34 76042 : var delegate_type = expr.value_type as DelegateType;
35 :
36 93229 : if (expr.symbol_reference is Method) {
37 17233 : var m = (Method) expr.symbol_reference;
38 :
39 17233 : if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArrayCopyMethod)) {
40 17215 : generate_method_declaration (m, cfile);
41 :
42 17215 : if (!m.external && m.external_package) {
43 : // internal VAPI methods
44 : // only add them once per source file
45 701 : if (add_generated_external_symbol (m)) {
46 183 : visit_method (m);
47 : }
48 : }
49 : }
50 :
51 17233 : if (expr.inner is BaseAccess) {
52 50 : CCodeExpression? vcast = null;
53 50 : if (m.base_method != null) {
54 43 : unowned Class base_class = (Class) m.base_method.parent_symbol;
55 43 : vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
56 43 : ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
57 7 : } else if (m.base_interface_method != null) {
58 3 : unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
59 3 : vcast = get_this_interface_cexpression (base_iface);
60 : }
61 46 : if (vcast != null) {
62 46 : set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
63 46 : return;
64 : }
65 : }
66 :
67 17187 : if (m.base_method != null) {
68 1519 : if (get_ccode_no_wrapper (m.base_method)) {
69 7 : unowned Class base_class = (Class) m.base_method.parent_symbol;
70 12 : if (!base_class.is_compact) {
71 5 : var vclass = get_this_class_cexpression (base_class, expr.inner.target_value);
72 5 : set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
73 : } else {
74 2 : set_cvalue (expr, new CCodeMemberAccess.pointer (pub_inst, get_ccode_vfunc_name (m)));
75 : }
76 : } else {
77 1512 : set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_method)));
78 : }
79 15668 : } else if (m.base_interface_method != null) {
80 280 : if (get_ccode_no_wrapper (m.base_interface_method)) {
81 7 : unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
82 7 : var vclass = get_this_interface_cexpression (base_iface, expr.inner.target_value);
83 7 : set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
84 : } else {
85 266 : set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_interface_method)));
86 : }
87 15395 : } else if (m is CreationMethod) {
88 5 : set_cvalue (expr, new CCodeIdentifier (get_ccode_real_name (m)));
89 : } else {
90 15390 : set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m)));
91 : }
92 :
93 17375 : delegate_type = expr.target_type as DelegateType;
94 17187 : if (delegate_type != null) {
95 188 : generate_type_declaration (delegate_type, cfile);
96 188 : set_cvalue (expr, new CCodeCastExpression (get_cvalue (expr), get_ccode_name (delegate_type.delegate_symbol)));
97 : }
98 :
99 17187 : set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
100 17187 : if (m.binding == MemberBinding.STATIC) {
101 7035 : set_delegate_target (expr, new CCodeConstant ("NULL"));
102 10152 : } else if (m.is_async_callback) {
103 21 : if (current_method.closure) {
104 2 : var block = ((Method) m.parent_symbol).body;
105 2 : set_delegate_target (expr, new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"));
106 : } else {
107 17 : set_delegate_target (expr, new CCodeIdentifier ("_data_"));
108 : }
109 20227 : } else if (expr.inner != null && !expr.prototype_access) {
110 : // expr.inner is null in the special case of referencing the method in a constant initializer
111 10094 : var delegate_target = (CCodeExpression) get_ccodenode (expr.inner);
112 10161 : delegate_type = expr.target_type as DelegateType;
113 10111 : if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.type_symbol != null && is_reference_counting (expr.inner.value_type.type_symbol)) {
114 17 : var ref_call = new CCodeFunctionCall (get_dup_func_expression (expr.inner.value_type, expr.source_reference));
115 17 : ref_call.add_argument (delegate_target);
116 34 : delegate_target = ref_call;
117 17 : set_delegate_target_destroy_notify (expr, get_destroy_func_expression (expr.inner.value_type));
118 : }
119 10094 : set_delegate_target (expr, delegate_target);
120 : }
121 58809 : } else if (expr.symbol_reference is ArrayLengthField) {
122 458 : set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
123 58365 : } else if (expr.symbol_reference is DelegateTargetField) {
124 : CCodeExpression delegate_target_destroy_notify;
125 14 : set_cvalue (expr, get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify) ?? new CCodeConstant ("NULL"));
126 58342 : } else if (expr.symbol_reference is DelegateDestroyField) {
127 : CCodeExpression delegate_target_destroy_notify;
128 5 : get_delegate_target_cexpression (expr.inner, out delegate_target_destroy_notify);
129 10 : set_cvalue (expr, delegate_target_destroy_notify ?? new CCodeConstant ("NULL"));
130 58332 : } else if (expr.symbol_reference is GenericDupField) {
131 16 : set_cvalue (expr, get_dup_func_expression (expr.inner.value_type, expr.source_reference));
132 58316 : } else if (expr.symbol_reference is GenericDestroyField) {
133 16 : set_cvalue (expr, get_destroy_func_expression (expr.inner.value_type));
134 65270 : } else if (expr.symbol_reference is Field) {
135 6970 : var field = (Field) expr.symbol_reference;
136 6970 : if (expr.lvalue) {
137 281 : expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
138 : } else {
139 6689 : expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null, expr);
140 : }
141 53124 : } else if (expr.symbol_reference is EnumValue) {
142 1794 : var ev = (EnumValue) expr.symbol_reference;
143 :
144 1794 : generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
145 :
146 1794 : set_cvalue (expr, new CCodeConstant (get_ccode_name (ev)));
147 50092 : } else if (expr.symbol_reference is Constant) {
148 556 : var c = (Constant) expr.symbol_reference;
149 :
150 556 : generate_constant_declaration (c, cfile,
151 556 : c.source_reference != null && expr.source_reference != null &&
152 556 : c.source_reference.file == expr.source_reference.file);
153 :
154 556 : string fn = c.get_full_name ();
155 556 : if (fn == "GLib.Log.FILE") {
156 1 : string s = Path.get_basename (expr.source_reference.file.filename);
157 1 : set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
158 555 : } else if (fn == "GLib.Log.LINE") {
159 1 : int i = expr.source_reference.begin.line;
160 1 : set_cvalue (expr, new CCodeConstant ("%d".printf (i)));
161 554 : } else if (fn == "GLib.Log.METHOD") {
162 1 : string s = "";
163 1 : if (current_method != null) {
164 1 : s = current_method.get_full_name ();
165 : }
166 1 : set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
167 553 : } else if (c.type_reference.is_non_null_simple_type ()) {
168 337 : set_cvalue (expr, new CCodeConstant (get_ccode_name (c)));
169 : } else {
170 216 : set_cvalue (expr, new CCodeConstantIdentifier (get_ccode_name (c)));
171 : }
172 :
173 556 : if (array_type != null) {
174 70 : string sub = "";
175 258 : for (int i = 0; i < array_type.rank; i++) {
176 : CCodeFunctionCall ccall;
177 94 : if (context.profile == Profile.POSIX) {
178 2 : requires_array_n_elements = true;
179 2 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("VALA_N_ELEMENTS"));
180 : } else {
181 92 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
182 : }
183 94 : ccall.add_argument (new CCodeIdentifier (get_ccode_name (c) + sub));
184 94 : append_array_length (expr, ccall);
185 94 : sub += "[0]";
186 : }
187 70 : ((GLibValue) expr.target_value).non_null = true;
188 : }
189 53679 : } else if (expr.symbol_reference is Property) {
190 4700 : var prop = (Property) expr.symbol_reference;
191 :
192 4700 : if (!(prop is DynamicProperty)) {
193 4684 : generate_property_accessor_declaration (prop.get_accessor, cfile);
194 :
195 4684 : if (!prop.external && prop.external_package) {
196 : // internal VAPI properties
197 : // only add them once per source file
198 21 : if (add_generated_external_symbol (prop)) {
199 5 : visit_property (prop);
200 : }
201 : }
202 : }
203 :
204 4700 : if (pub_inst == null && prop.binding == MemberBinding.INSTANCE) {
205 : // FIXME Report this with proper source-reference on the vala side!
206 1 : Report.error (prop.source_reference, "Invalid access to instance member `%s'", prop.get_full_name ());
207 1 : set_cvalue (expr, new CCodeInvalidExpression ());
208 1 : return;
209 : }
210 :
211 4699 : unowned Property base_prop = prop;
212 4699 : if (prop.base_property != null) {
213 22 : base_prop = prop.base_property;
214 4677 : } else if (prop.base_interface_property != null) {
215 195 : base_prop = prop.base_interface_property;
216 : }
217 4704 : if (expr.inner is BaseAccess && (base_prop.is_abstract || base_prop.is_virtual)) {
218 5 : CCodeExpression? vcast = null;
219 5 : if (base_prop.parent_symbol is Class) {
220 3 : unowned Class base_class = (Class) base_prop.parent_symbol;
221 3 : vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
222 3 : ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
223 2 : } else if (base_prop.parent_symbol is Interface) {
224 2 : unowned Interface base_iface = (Interface) base_prop.parent_symbol;
225 2 : vcast = get_this_interface_cexpression (base_iface);
226 : }
227 10 : if (vcast != null) {
228 5 : var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
229 5 : ccall.add_argument (get_cvalue (expr.inner));
230 8 : if (prop.property_type.is_real_non_null_struct_type ()) {
231 3 : var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
232 3 : expr.target_value = load_temp_value (temp_value);
233 3 : var ctemp = get_cvalue_ (temp_value);
234 3 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
235 3 : ccode.add_expression (ccall);
236 : } else {
237 2 : set_cvalue (expr, ccall);
238 : }
239 : } else {
240 0 : Report.error (expr.source_reference, "internal: Invalid access to `%s'", base_prop.get_full_name ());
241 : }
242 5020 : } else if (prop.binding == MemberBinding.INSTANCE &&
243 4693 : prop.get_accessor.automatic_body &&
244 1229 : !prop.get_accessor.value_type.value_owned &&
245 1199 : current_type_symbol == prop.parent_symbol &&
246 326 : current_type_symbol is Class &&
247 326 : prop.base_property == null &&
248 326 : prop.base_interface_property == null &&
249 326 : !(prop.property_type is ArrayType || prop.property_type is DelegateType)) {
250 326 : CCodeExpression inst = pub_inst;
251 326 : if (!((Class) current_type_symbol).is_compact) {
252 325 : inst = new CCodeMemberAccess.pointer (inst, "priv");
253 : }
254 326 : set_cvalue (expr, new CCodeMemberAccess.pointer (inst, get_ccode_name (prop.field)));
255 8736 : } else if (!get_ccode_no_accessor_method (prop) && !(prop is DynamicProperty)) {
256 4344 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.get_accessor)));
257 :
258 4344 : if (prop.binding == MemberBinding.INSTANCE) {
259 4351 : if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
260 : // we need to pass struct instance by reference
261 39742 : var instance = expr.inner.target_value;
262 8 : if (!get_lvalue (instance)) {
263 0 : instance = store_temp_value (instance, expr);
264 : }
265 8 : pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
266 : }
267 :
268 4343 : ccall.add_argument (pub_inst);
269 : }
270 :
271 4344 : bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type ();
272 4344 : bool requires_init = prop.property_type is DelegateType || prop_is_real_non_null_struct_type;
273 4344 : var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, requires_init, expr);
274 4344 : expr.target_value = load_temp_value (temp_value);
275 4344 : var ctemp = get_cvalue_ (temp_value);
276 :
277 : // Property access to real struct types is handled differently
278 : // The value is returned by out parameter
279 4344 : if (prop_is_real_non_null_struct_type) {
280 79 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
281 79 : ccode.add_expression (ccall);
282 : } else {
283 4291 : array_type = prop.property_type as ArrayType;
284 4265 : if (array_type != null) {
285 34 : if (get_ccode_array_null_terminated (prop) && !get_ccode_array_length (prop)) {
286 8 : requires_array_length = true;
287 8 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
288 8 : len_call.add_argument (ctemp);
289 :
290 8 : ccode.add_assignment (ctemp, ccall);
291 8 : ccode.add_assignment (temp_value.array_length_cvalues[0], len_call);
292 36 : } else if (get_ccode_array_length (prop)) {
293 18 : var temp_refs = new ArrayList<CCodeExpression> ();
294 36 : for (int dim = 1; dim <= array_type.rank; dim++) {
295 18 : var length_ctype = get_ccode_array_length_type (prop);
296 18 : var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
297 18 : var temp_ref = get_variable_cexpression (temp_var.name);
298 18 : emit_temp_var (temp_var);
299 18 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
300 18 : temp_refs.add (temp_ref);
301 : }
302 :
303 18 : ccode.add_assignment (ctemp, ccall);
304 36 : for (int dim = 1; dim <= array_type.rank; dim++) {
305 18 : ccode.add_assignment (temp_value.array_length_cvalues[dim - 1], temp_refs.get (dim - 1));
306 : }
307 : } else {
308 0 : ccode.add_assignment (ctemp, ccall);
309 : }
310 : } else {
311 4239 : ccode.add_assignment (ctemp, ccall);
312 :
313 4249 : delegate_type = prop.property_type as DelegateType;
314 4239 : if (delegate_type != null && get_ccode_delegate_target (prop) && delegate_type.delegate_symbol.has_target) {
315 6 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue (temp_value)));
316 : } else {
317 4233 : if (temp_value.delegate_target_cvalue != null) {
318 4 : ccode.add_assignment (temp_value.delegate_target_cvalue, new CCodeConstant ("NULL"));
319 : }
320 4233 : if (temp_value.delegate_target_destroy_notify_cvalue != null) {
321 0 : ccode.add_assignment (temp_value.delegate_target_destroy_notify_cvalue, new CCodeConstant ("NULL"));
322 : }
323 : }
324 : }
325 : }
326 : } else {
327 24 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
328 24 : ccall.add_argument (pub_inst);
329 :
330 : // property name is second argument of g_object_get
331 24 : ccall.add_argument (get_property_canonical_cconstant (prop));
332 :
333 : // g_object_get always returns owned values
334 : // therefore, property getters of properties
335 : // without accessor methods need to be marked as owned
336 24 : if (!(prop is DynamicProperty) && !prop.get_accessor.value_type.value_owned) {
337 : // only report error for types where there actually
338 : // is a difference between `owned' and `unowned'
339 0 : var owned_value_type = prop.get_accessor.value_type.copy ();
340 0 : owned_value_type.value_owned = true;
341 0 : if (requires_copy (owned_value_type)) {
342 0 : Report.error (prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor", prop.get_full_name ());
343 : }
344 : }
345 :
346 24 : if (expr.value_type.is_real_struct_type ()) {
347 : // gobject allocates structs on heap
348 5 : expr.value_type.nullable = true;
349 : }
350 :
351 24 : var temp_var = get_temp_variable (expr.value_type);
352 24 : var ctemp = get_variable_cexpression (temp_var.name);
353 24 : emit_temp_var (temp_var);
354 24 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
355 24 : ccall.add_argument (new CCodeConstant ("NULL"));
356 24 : ccode.add_expression (ccall);
357 :
358 24 : set_cvalue (expr, ctemp);
359 :
360 25 : if (get_ccode_array_null_terminated (prop) && !get_ccode_array_length (prop)) {
361 1 : requires_array_length = true;
362 1 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
363 1 : len_call.add_argument (ctemp);
364 :
365 1 : var glib_value = (GLibValue) expr.target_value;
366 1 : glib_value.array_length_cvalues = null;
367 1 : glib_value.append_array_length_cvalue (len_call);
368 1 : glib_value.lvalue = false;
369 : }
370 : }
371 :
372 4699 : if (prop.get_accessor.value_type is GenericType) {
373 9 : expr.target_value.value_type = prop.get_accessor.value_type.copy ();
374 : } else {
375 4690 : expr.target_value.value_type = expr.value_type.copy ();
376 : }
377 4699 : expr.target_value = store_temp_value (expr.target_value, expr);
378 61238 : } else if (expr.symbol_reference is LocalVariable) {
379 16958 : var local = (LocalVariable) expr.symbol_reference;
380 :
381 17223 : if (expr.parent_node is ReturnStatement &&
382 314 : current_return_type.value_owned &&
383 306 : local.variable_type.value_owned &&
384 274 : !local.captured &&
385 268 : !variable_accessible_in_finally (local) &&
386 266 : !(local.variable_type is ArrayType && ((ArrayType) local.variable_type).inline_allocated)) {
387 : /* return expression is local variable taking ownership and
388 : * current method is transferring ownership */
389 :
390 : // don't ref expression
391 265 : expr.value_type.value_owned = true;
392 :
393 : // don't unref variable
394 265 : local.active = false;
395 :
396 265 : var glib_value = (GLibValue) get_local_cvalue (local);
397 265 : expr.target_value = glib_value;
398 265 : if (glib_value.delegate_target_cvalue == null) {
399 265 : glib_value.delegate_target_cvalue = new CCodeConstant ("NULL");
400 : }
401 265 : if (glib_value.delegate_target_destroy_notify_cvalue == null) {
402 265 : glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
403 : }
404 : } else {
405 16693 : if (expr.lvalue) {
406 1048 : expr.target_value = get_local_cvalue (local);
407 : } else {
408 15645 : expr.target_value = load_local (local, expr);
409 : }
410 : }
411 43828 : } else if (expr.symbol_reference is Parameter) {
412 16506 : var param = (Parameter) expr.symbol_reference;
413 16506 : if (expr.lvalue) {
414 107 : expr.target_value = get_parameter_cvalue (param);
415 : } else {
416 16399 : expr.target_value = load_parameter (param, expr);
417 : }
418 : }
419 :
420 : // Add cast for narrowed type access of variables if needed
421 75995 : if (expr.symbol_reference is Variable) {
422 40943 : unowned GLibValue cvalue = (GLibValue) expr.target_value;
423 40943 : if (!(cvalue.value_type is GenericType) && cvalue.value_type.type_symbol != null
424 37999 : && cvalue.value_type.type_symbol != expr.value_type.type_symbol) {
425 1 : cvalue.cvalue = new CCodeCastExpression (cvalue.cvalue, get_ccode_name (expr.value_type));
426 : }
427 : }
428 : }
429 :
430 : /* Returns lvalue access to the given local variable */
431 67179 : public override TargetValue get_local_cvalue (LocalVariable local) {
432 67179 : var result = new GLibValue (local.variable_type.copy ());
433 67179 : result.lvalue = true;
434 :
435 67179 : var array_type = local.variable_type as ArrayType;
436 67179 : var delegate_type = local.variable_type as DelegateType;
437 67179 : if (local.is_result) {
438 : // used in postconditions
439 : // structs are returned as out parameter
440 15 : if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type ()) {
441 0 : result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
442 : } else {
443 15 : result.cvalue = new CCodeIdentifier ("result");
444 : }
445 15 : if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null)) {
446 10 : for (int dim = 1; dim <= array_type.rank; dim++) {
447 5 : result.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_array_length_cname ("result", dim))));
448 : }
449 : }
450 67460 : } else if (local.captured) {
451 : // captured variables are stored on the heap
452 296 : var block = (Block) local.parent_symbol;
453 296 : result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_local_cname (local));
454 296 : if (array_type != null && !array_type.fixed_length) {
455 34 : for (int dim = 1; dim <= array_type.rank; dim++) {
456 17 : result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_local_cname (local), dim)));
457 : }
458 17 : if (array_type.rank == 1) {
459 17 : result.array_size_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_size_cname (get_local_cname (local)));
460 : }
461 279 : } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
462 8 : result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_local_cname (local)));
463 8 : if (delegate_type.is_disposable ()) {
464 6 : result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
465 : }
466 : }
467 : } else {
468 66868 : result.cvalue = get_local_cexpression (local);
469 66868 : if (array_type != null && !array_type.fixed_length) {
470 9311 : for (int dim = 1; dim <= array_type.rank; dim++) {
471 4766 : result.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local), dim)));
472 : }
473 4545 : if (array_type.rank == 1) {
474 4403 : result.array_size_cvalue = get_variable_cexpression (get_array_size_cname (get_local_cname (local)));
475 : }
476 62323 : } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
477 367 : if (is_in_coroutine ()) {
478 21 : result.delegate_target_cvalue = get_variable_cexpression (get_delegate_target_cname (get_local_cname (local)));
479 21 : if (local.variable_type.is_disposable ()) {
480 19 : result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
481 : }
482 : } else {
483 346 : result.delegate_target_cvalue = new CCodeIdentifier (get_delegate_target_cname (get_local_cname (local)));
484 346 : if (local.variable_type.is_disposable ()) {
485 253 : result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
486 : }
487 : }
488 : }
489 : }
490 :
491 67179 : return result;
492 : }
493 :
494 : /* Returns access values to the given parameter */
495 18198 : public override TargetValue get_parameter_cvalue (Parameter param) {
496 18198 : var result = new GLibValue (param.variable_type.copy ());
497 18198 : result.lvalue = true;
498 18198 : result.array_null_terminated = get_ccode_array_null_terminated (param);
499 18198 : if (get_ccode_array_length_expr (param) != null) {
500 0 : result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (param));
501 : }
502 18198 : result.ctype = get_ccode_type (param);
503 :
504 18198 : var array_type = result.value_type as ArrayType;
505 18198 : var delegate_type = result.value_type as DelegateType;
506 :
507 176 : bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;
508 18198 : if ((param.captured || is_in_coroutine ()) && !is_unowned_delegate) {
509 303 : result.value_type.value_owned = true;
510 : }
511 :
512 26355 : if (param.name == "this") {
513 10041 : if (is_in_coroutine ()) {
514 : // use closure
515 100 : result.cvalue = get_this_cexpression ();
516 : } else {
517 9941 : unowned Struct? st = result.value_type.type_symbol as Struct;
518 9941 : if (st != null && !st.is_simple_type ()) {
519 185 : result.cvalue = new CCodeIdentifier ("(*self)");
520 : } else {
521 9756 : result.cvalue = new CCodeIdentifier ("self");
522 : }
523 : }
524 : } else {
525 8157 : string name = get_ccode_name (param);
526 :
527 8251 : if (param.captured && !is_in_method_precondition) {
528 : // captured variables are stored on the heap
529 94 : var block = param.parent_symbol as Block;
530 94 : if (block == null) {
531 92 : block = ((Method) param.parent_symbol).body;
532 : }
533 94 : result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_name (param));
534 94 : if (array_type != null && get_ccode_array_length (param)) {
535 4 : for (int dim = 1; dim <= array_type.rank; dim++) {
536 2 : result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_array_length_cname (param, dim)));
537 : }
538 92 : } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
539 26 : result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_name (param));
540 26 : if (result.value_type.is_disposable ()) {
541 4 : result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_destroy_notify_name (param));
542 : }
543 : }
544 8063 : } else if (is_in_coroutine ()) {
545 : // use closure
546 133 : result.cvalue = get_parameter_cexpression (param);
547 133 : if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
548 9 : result.delegate_target_cvalue = get_variable_cexpression (get_ccode_delegate_target_name (param));
549 9 : if (delegate_type.is_disposable ()) {
550 9 : result.delegate_target_destroy_notify_cvalue = get_variable_cexpression (get_ccode_delegate_target_destroy_notify_name (param));
551 : }
552 : }
553 : } else {
554 7930 : unowned Struct? type_as_struct = result.value_type.type_symbol as Struct;
555 :
556 7930 : if (param.direction == ParameterDirection.OUT) {
557 445 : name = "_vala_%s".printf (name);
558 : }
559 :
560 7930 : if (param.direction == ParameterDirection.REF ||
561 7829 : (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type () && !result.value_type.nullable)) {
562 160 : result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (name));
563 : } else {
564 7770 : result.cvalue = get_variable_cexpression (name);
565 : }
566 8035 : if (get_ccode_delegate_target (param) && delegate_type != null && delegate_type.delegate_symbol.has_target) {
567 105 : var target_cname = get_ccode_delegate_target_name (param);
568 105 : var destroy_cname = get_ccode_delegate_target_destroy_notify_name (param);
569 105 : if (param.direction == ParameterDirection.OUT) {
570 10 : target_cname = "_vala_%s".printf (target_cname);
571 10 : destroy_cname = "_vala_%s".printf (destroy_cname);
572 : }
573 105 : CCodeExpression target_expr = new CCodeIdentifier (target_cname);
574 105 : CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier (destroy_cname);
575 105 : if (param.direction == ParameterDirection.REF) {
576 : // accessing argument of ref param
577 3 : target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
578 3 : delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
579 : }
580 210 : result.delegate_target_cvalue = target_expr;
581 105 : if (result.value_type.is_disposable ()) {
582 124 : result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
583 : }
584 : }
585 : }
586 8157 : if (!param.captured && array_type != null) {
587 546 : if (get_ccode_array_length (param) && !get_ccode_array_null_terminated (param)) {
588 1624 : for (int dim = 1; dim <= array_type.rank; dim++) {
589 558 : CCodeExpression length_expr = get_cexpression (get_variable_array_length_cname (param, dim));
590 558 : if (param.direction == ParameterDirection.OUT) {
591 103 : length_expr = get_cexpression (get_array_length_cname (name, dim));
592 455 : } else if (param.direction == ParameterDirection.REF) {
593 : // accessing argument of ref param
594 24 : length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
595 : }
596 558 : result.append_array_length_cvalue (length_expr);
597 : }
598 : }
599 : }
600 : }
601 :
602 18198 : return result;
603 : }
604 :
605 : /* Returns lvalue access to the given field */
606 11146 : public override TargetValue get_field_cvalue (Field field, TargetValue? instance) {
607 11146 : var value_type = field.variable_type.copy ();
608 :
609 11146 : var result = new GLibValue (value_type);
610 11146 : if (instance != null) {
611 9201 : result.actual_value_type = field.variable_type.get_actual_type (instance.value_type, null, field);
612 : }
613 11146 : result.lvalue = true;
614 11146 : result.array_null_terminated = get_ccode_array_null_terminated (field);
615 11146 : if (get_ccode_array_length_expr (field) != null) {
616 0 : result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (field));
617 : }
618 11146 : result.ctype = get_ccode_type (field);
619 :
620 11146 : var array_type = result.value_type as ArrayType;
621 20328 : if (field.binding == MemberBinding.INSTANCE) {
622 9183 : CCodeExpression pub_inst = null;
623 :
624 9183 : if (instance != null) {
625 9182 : pub_inst = get_cvalue_ (instance);
626 : }
627 :
628 9183 : var instance_target_type = SemanticAnalyzer.get_data_type_for_symbol (field.parent_symbol);
629 :
630 9183 : unowned Class? cl = instance_target_type.type_symbol as Class;
631 19516 : bool is_gtypeinstance = ((instance_target_type.type_symbol == cl) && (cl == null || !cl.is_compact));
632 :
633 : CCodeExpression inst;
634 8186 : if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
635 5498 : inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
636 : } else {
637 3685 : if (cl != null) {
638 2688 : generate_class_struct_declaration (cl, cfile);
639 : }
640 3685 : inst = pub_inst;
641 : }
642 :
643 9183 : if (inst == null) {
644 : // FIXME Report this with proper source-reference on the vala side!
645 1 : Report.error (field.source_reference, "Invalid access to instance member `%s'", field.get_full_name ());
646 1 : result.cvalue = new CCodeInvalidExpression ();
647 1 : return result;
648 : }
649 :
650 9182 : if (instance_target_type.type_symbol.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
651 8185 : result.cvalue = new CCodeMemberAccess.pointer (inst, get_ccode_name (field));
652 : } else {
653 997 : result.cvalue = new CCodeMemberAccess (inst, get_ccode_name (field));
654 : }
655 :
656 9182 : if (array_type != null && get_ccode_array_length (field)) {
657 1083 : for (int dim = 1; dim <= array_type.rank; dim++) {
658 364 : CCodeExpression length_expr = null;
659 364 : string length_cname = get_variable_array_length_cname (field, dim);
660 :
661 364 : if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
662 285 : length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
663 : } else {
664 79 : length_expr = new CCodeMemberAccess (inst, length_cname);
665 : }
666 :
667 364 : result.append_array_length_cvalue (length_expr);
668 : }
669 587 : if (array_type.rank == 1 && field.is_internal_symbol ()) {
670 232 : string size_cname = get_array_size_cname (get_ccode_name (field));
671 :
672 232 : if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
673 173 : set_array_size_cvalue (result, new CCodeMemberAccess.pointer (inst, size_cname));
674 : } else {
675 59 : set_array_size_cvalue (result, new CCodeMemberAccess (inst, size_cname));
676 : }
677 : }
678 8919 : } else if (get_ccode_delegate_target (field)) {
679 92 : string target_cname = get_ccode_delegate_target_name (field);
680 92 : string target_destroy_notify_cname = get_ccode_delegate_target_destroy_notify_name (field);
681 :
682 92 : if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
683 83 : result.delegate_target_cvalue = new CCodeMemberAccess.pointer (inst, target_cname);
684 83 : if (result.value_type.is_disposable ()){
685 79 : result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
686 : }
687 : } else {
688 9 : result.delegate_target_cvalue = new CCodeMemberAccess (inst, target_cname);
689 9 : if (result.value_type.is_disposable ()) {
690 6 : result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess (inst, target_destroy_notify_cname);
691 : }
692 : }
693 : }
694 2083 : } else if (field.binding == MemberBinding.CLASS) {
695 120 : unowned Class cl = (Class) field.parent_symbol;
696 120 : var cast = get_this_class_cexpression (cl, instance);
697 157 : if (field.access == SymbolAccessibility.PRIVATE) {
698 37 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_get_private_function (cl)));
699 37 : ccall.add_argument (cast);
700 37 : result.cvalue = new CCodeMemberAccess.pointer (ccall, get_ccode_name (field));
701 : } else {
702 83 : result.cvalue = new CCodeMemberAccess.pointer (cast, get_ccode_name (field));
703 : }
704 :
705 : } else {
706 1843 : generate_field_declaration (field, cfile);
707 :
708 1843 : result.cvalue = new CCodeIdentifier (get_ccode_name (field));
709 :
710 1843 : if (array_type != null && get_ccode_array_length (field)) {
711 182 : for (int dim = 1; dim <= array_type.rank; dim++) {
712 91 : string length_cname = get_variable_array_length_cname (field, dim);
713 91 : result.append_array_length_cvalue (new CCodeIdentifier (length_cname));
714 : }
715 91 : if (array_type.rank == 1 && field.is_internal_symbol ()) {
716 88 : set_array_size_cvalue (result, new CCodeIdentifier (get_array_size_cname (get_ccode_name (field))));
717 : }
718 1752 : } else if (get_ccode_delegate_target (field)) {
719 3 : result.delegate_target_cvalue = new CCodeIdentifier (get_ccode_delegate_target_name (field));
720 3 : if (result.value_type.is_disposable ()) {
721 2 : result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_ccode_delegate_target_destroy_notify_name (field));
722 : }
723 : }
724 : }
725 :
726 11145 : return result;
727 : }
728 :
729 39733 : public override TargetValue load_variable (Variable variable, TargetValue value, Expression? expr = null) {
730 39733 : var result = (GLibValue) value;
731 39733 : var array_type = result.value_type as ArrayType;
732 39733 : var delegate_type = result.value_type as DelegateType;
733 39733 : if (array_type != null) {
734 2177 : if (array_type.fixed_length) {
735 132 : result.array_length_cvalues = null;
736 132 : result.append_array_length_cvalue (get_ccodenode (array_type.length));
737 132 : result.lvalue = false;
738 2130 : } else if (get_ccode_array_null_terminated (variable) && !get_ccode_array_length (variable)) {
739 85 : requires_array_length = true;
740 85 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
741 85 : len_call.add_argument (result.cvalue);
742 :
743 85 : result.array_length_cvalues = null;
744 85 : result.append_array_length_cvalue (len_call);
745 85 : result.lvalue = false;
746 1960 : } else if (get_ccode_array_length_expr (variable) != null) {
747 0 : var length_expr = new CCodeConstant (get_ccode_array_length_expr (variable));
748 :
749 0 : result.array_length_cvalues = null;
750 0 : result.append_array_length_cvalue (length_expr);
751 0 : result.lvalue = false;
752 1960 : } else if (!get_ccode_array_length (variable)) {
753 25 : result.array_length_cvalues = null;
754 50 : for (int dim = 1; dim <= array_type.rank; dim++) {
755 25 : result.append_array_length_cvalue (new CCodeConstant ("-1"));
756 : }
757 25 : result.lvalue = false;
758 1935 : } else if (get_ccode_array_length_type (variable.variable_type) != get_ccode_array_length_type (array_type)) {
759 0 : for (int dim = 1; dim <= array_type.rank; dim++) {
760 : // cast if variable does not use int for array length
761 0 : result.array_length_cvalues[dim - 1] = new CCodeCastExpression (result.array_length_cvalues[dim - 1], get_ccode_array_length_type (array_type));
762 : }
763 0 : result.lvalue = false;
764 : }
765 2177 : result.array_size_cvalue = null;
766 2177 : result.non_null = array_type.inline_allocated;
767 37556 : } else if (delegate_type != null) {
768 448 : if (!get_ccode_delegate_target (variable)) {
769 271 : result.delegate_target_cvalue = new CCodeConstant ("NULL");
770 271 : result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
771 : }
772 :
773 448 : result.lvalue = false;
774 : }
775 39733 : result.value_type.value_owned = false;
776 :
777 39733 : bool use_temp = true;
778 39733 : if (!is_lvalue_access_allowed (result.value_type)) {
779 : // special handling for types such as va_list
780 148 : use_temp = false;
781 : }
782 56996 : if (variable is Parameter) {
783 17263 : var param = (Parameter) variable;
784 17263 : if (variable.name == "this") {
785 : use_temp = false;
786 7296 : } else if ((param.direction != ParameterDirection.OUT)
787 7278 : && !(param.variable_type.is_real_non_null_struct_type ())) {
788 17197 : use_temp = false;
789 : }
790 : }
791 39733 : if (variable.single_assignment && !result.value_type.is_real_non_null_struct_type ()) {
792 : // no need to copy values from variables that are assigned exactly once
793 : // as there is no risk of modification
794 : // except for structs that are always passed by reference
795 39733 : use_temp = false;
796 : }
797 39733 : if (result.value_type.is_non_null_simple_type ()) {
798 : // no need to an extra copy of variables that are stack allocated simple types
799 5970 : use_temp = false;
800 : }
801 : // our implementation of postfix-expressions require temporary variables
802 39733 : if (expr is MemberAccess && ((MemberAccess) expr).tainted_access) {
803 39733 : use_temp = true;
804 : }
805 :
806 39733 : var local = variable as LocalVariable;
807 15689 : if (local != null && local.name[0] == '.') {
808 : // already a temporary variable generated internally
809 : // and safe to access without temporary variable
810 : use_temp = false;
811 : }
812 :
813 38217 : if (use_temp) {
814 14764 : result = (GLibValue) store_temp_value (result, variable);
815 : }
816 :
817 39733 : return result;
818 : }
819 :
820 : /* Returns unowned access to the given local variable */
821 15689 : public override TargetValue load_local (LocalVariable local, Expression? expr = null) {
822 15689 : return load_variable (local, get_local_cvalue (local), expr);
823 : }
824 :
825 : /* Returns unowned access to the given parameter */
826 17263 : public override TargetValue load_parameter (Parameter param, Expression? expr = null) {
827 17263 : return load_variable (param, get_parameter_cvalue (param), expr);
828 : }
829 :
830 : /* Convenience method returning access to "this" */
831 801 : public override TargetValue load_this_parameter (TypeSymbol sym) {
832 801 : var param = new Parameter ("this", SemanticAnalyzer.get_data_type_for_symbol (sym));
833 801 : return load_parameter (param);
834 : }
835 :
836 : /* Returns unowned access to the given field */
837 6781 : public override TargetValue load_field (Field field, TargetValue? instance, Expression? expr = null) {
838 6781 : return load_variable (field, get_field_cvalue (field, instance), expr);
839 : }
840 : }
|