Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
native_location.h
Go to the documentation of this file.
1// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
6#define RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include "platform/assert.h"
15#include "vm/constants.h"
16#include "vm/growable_array.h"
17
18#if !defined(FFI_UNIT_TESTS)
20#endif
21
22namespace dart {
23
24class BaseTextBuffer;
25
26namespace compiler {
27
28namespace ffi {
29
30class NativeRegistersLocation;
31class NativeFpuRegistersLocation;
32class NativeStackLocation;
33class MultipleNativeLocations;
34class PointerToMemoryLocation;
35class BothNativeLocations;
36
37// NativeLocation objects are used in the FFI to describe argument and return
38// value locations in all native ABIs that the FFI supports.
39//
40// NativeLocations contain two NativeTypes.
41// * The payload type.
42// * The container type, equal to or larger than the payload. If the
43// container is larger than the payload, the upper bits are defined by sign
44// or zero extension.
45// Container type is also used to denote an integer container when floating
46// point values are passed in integer registers.
47//
48// NativeLocations can express things that dart::Locations cannot express:
49// * Multiple consecutive registers.
50// * Multiple sizes of FPU registers (e.g. S, D, and Q on Arm32).
51// * Arbitrary byte-size stack locations, at byte-size offsets.
52// (The Location class uses word-size offsets.)
53// * Pointers to a memory location.
54// * Split between multiple registers and stack.
55//
56// NativeLocations cannot express the following dart::Locations:
57// * No PairLocations. Instead, NativeRegistersLocations can have multiple
58// registers, and NativeStackLocations can have arbitrary types.
59// * No ConstantLocations.
60//
61// NativeLocation does not satisfy the invariant of Location: bitwise
62// inequality cannot be used to determine disjointness.
64 public:
65#if !defined(FFI_UNIT_TESTS)
67 static NativeLocation& FromLocation(Zone* zone,
68 Location loc,
69 Representation rep);
71 Location loc,
73 intptr_t index);
74#endif
75
76 // The type of the data at this location.
77 const NativeType& payload_type() const { return payload_type_; }
78
79 // The location container size, possibly larger than data.
80 //
81 // If the container is larger than the data, the remaining bits are _not_
82 // undefined. For example a uint8 inside a uint32 has the upper 24 bits set
83 // to 0. Effectively allowing the value to be read as uint8, uint16 and
84 // uint32.
85 const NativeType& container_type() const { return container_type_; }
86
88 Zone* zone,
89 const NativeType& new_payload_type,
90 const NativeType& new_container_type) const = 0;
91
92#if defined(TARGET_ARCH_ARM)
93 const NativeLocation& WidenToQFpuRegister(Zone* zone) const;
94#endif // defined(TARGET_ARCH_ARM)
95
96 NativeLocation& WidenTo4Bytes(Zone* zone) const;
97 NativeLocation& WidenTo8Bytes(Zone* zone) const;
98
99 virtual bool IsRegisters() const { return false; }
100 virtual bool IsFpuRegisters() const { return false; }
101 virtual bool IsStack() const { return false; }
102 virtual bool IsMultiple() const { return false; }
103 virtual bool IsPointerToMemory() const { return false; }
104 virtual bool IsBoth() const { return false; }
105
106 virtual bool IsExpressibleAsLocation() const { return false; }
107#if !defined(FFI_UNIT_TESTS)
108 virtual Location AsLocation() const {
111 }
112#endif
113
114 virtual void PrintTo(BaseTextBuffer* f) const;
115 const char* ToCString(Zone* zone) const;
116#if !defined(FFI_UNIT_TESTS)
117 const char* ToCString() const;
118#endif
119
122 const NativeStackLocation& AsStack() const;
123 const MultipleNativeLocations& AsMultiple() const;
125 const BothNativeLocations& AsBoth() const;
126
127 // Retrieve one part from this location when it is split into multiple parts.
128 virtual NativeLocation& Split(Zone* zone,
129 intptr_t num_parts,
130 intptr_t index) const {
132 }
133
134 // Return the top of the stack in bytes. Recurses over its constituents when
135 // MultipleNativeLocations.
136 virtual intptr_t StackTopInBytes() const { return 0; }
137
138 // Equality of location, ignores the payload and container native types.
139 virtual bool Equals(const NativeLocation& other) const { UNREACHABLE_THIS(); }
140
141 virtual ~NativeLocation() {}
142
143 protected:
146 : payload_type_(payload_type), container_type_(container_type) {}
147
148 private:
149 const NativeType& payload_type_;
150 // The location container size, possibly larger than data.
151 //
152 // If the container is larger than the data, the remaining bits are _not_
153 // undefined. For example a uint8 inside a uint32 has the upper 24 bits set
154 // to 0. Effectively allowing the value to be read as uint8, uint16 and
155 // uint32.
156 const NativeType& container_type_;
157};
158
160 public:
168 Register reg)
170 regs_ = new (zone) ZoneGrowableArray<Register>(zone, 1);
171 regs_->Add(reg);
172 }
176 Register register1,
177 Register register2)
179 regs_ = new (zone) ZoneGrowableArray<Register>(zone, 2);
180 regs_->Add(register1);
181 regs_->Add(register2);
182 }
184
186 Zone* zone,
187 const NativeType& new_payload_type,
188 const NativeType& new_container_type) const {
189 return *new (zone)
190 NativeRegistersLocation(new_payload_type, new_container_type, regs_);
191 }
192
193 virtual bool IsRegisters() const { return true; }
194 virtual bool IsExpressibleAsLocation() const {
195 return num_regs() == 1 || num_regs() == 2;
196 }
197#if !defined(FFI_UNIT_TESTS)
198 virtual Location AsLocation() const;
199#endif
200 intptr_t num_regs() const { return regs_->length(); }
201 Register reg_at(intptr_t index) const { return regs_->At(index); }
202
203 virtual NativeRegistersLocation& Split(Zone* zone,
204 intptr_t num_parts,
205 intptr_t index) const;
206
207 virtual void PrintTo(BaseTextBuffer* f) const;
208
209 virtual bool Equals(const NativeLocation& other) const;
210
211 private:
213
215};
216
218 kQuadFpuReg, // 16 bytes
219 kDoubleFpuReg, // 8 bytes, a double
220 kSingleFpuReg // 4 bytes, a float
222
224FpuRegisterKind FpuRegisterKindFromSize(intptr_t size_in_bytes);
225
227 public:
231 intptr_t fpu_register)
233 fpu_reg_kind_(fpu_reg_kind),
234 fpu_reg_(fpu_register) {}
237 FpuRegister fpu_register)
239 fpu_reg_kind_(kQuadFpuReg),
240 fpu_reg_(fpu_register) {}
241#if defined(TARGET_ARCH_ARM)
244 DRegister fpu_register)
246 fpu_reg_kind_(kDoubleFpuReg),
247 fpu_reg_(fpu_register) {}
248 NativeFpuRegistersLocation(const NativeType& payload_type,
249 const NativeType& container_type,
250 SRegister fpu_register)
251 : NativeLocation(payload_type, container_type),
252 fpu_reg_kind_(kSingleFpuReg),
253 fpu_reg_(fpu_register) {}
254#endif // defined(TARGET_ARCH_ARM)
256
258 Zone* zone,
259 const NativeType& new_payload_type,
260 const NativeType& new_container_type) const {
261 return *new (zone) NativeFpuRegistersLocation(
262 new_payload_type, new_container_type, fpu_reg_kind_, fpu_reg_);
263 }
264 virtual bool IsFpuRegisters() const { return true; }
265 virtual bool IsExpressibleAsLocation() const {
266 return fpu_reg_kind_ == kQuadFpuReg;
267 }
268#if !defined(FFI_UNIT_TESTS)
273#endif
274 FpuRegisterKind fpu_reg_kind() const { return fpu_reg_kind_; }
276 ASSERT(fpu_reg_kind_ == kQuadFpuReg);
277 return static_cast<FpuRegister>(fpu_reg_);
278 }
279#if defined(TARGET_ARCH_ARM)
280 DRegister fpu_d_reg() const {
281 ASSERT(fpu_reg_kind_ == kDoubleFpuReg);
282 return static_cast<DRegister>(fpu_reg_);
283 }
284 SRegister fpu_s_reg() const {
285 ASSERT(fpu_reg_kind_ == kSingleFpuReg);
286 return static_cast<SRegister>(fpu_reg_);
287 }
288 DRegister fpu_as_d_reg() const;
289 SRegister fpu_as_s_reg() const;
290
291 bool IsLowestBits() const;
292#endif // defined(TARGET_ARCH_ARM)
293
294 virtual void PrintTo(BaseTextBuffer* f) const;
295
296 virtual bool Equals(const NativeLocation& other) const;
297
298 private:
299 FpuRegisterKind fpu_reg_kind_;
300 intptr_t fpu_reg_;
301 DISALLOW_COPY_AND_ASSIGN(NativeFpuRegistersLocation);
302};
303
305 public:
314
316 Zone* zone,
317 const NativeType& new_payload_type,
318 const NativeType& new_container_type) const {
319 return *new (zone) NativeStackLocation(new_payload_type, new_container_type,
320 base_register_, offset_in_bytes_);
321 }
322
323 virtual bool IsStack() const { return true; }
324 virtual bool IsExpressibleAsLocation() const {
325 const intptr_t size = payload_type().SizeInBytes();
326 const intptr_t size_slots = size / compiler::target::kWordSize;
327 return offset_in_bytes_ % compiler::target::kWordSize == 0 &&
328 size % compiler::target::kWordSize == 0 &&
329 (size_slots == 1 || size_slots == 2);
330 }
331
332#if !defined(FFI_UNIT_TESTS)
333 virtual Location AsLocation() const;
334
335 // ConstantInstr expects DoubleStackSlot for doubles, even on 64-bit systems.
336 //
337 // So this return a wrong-sized Location on purpose.
339 ASSERT(compiler::target::kWordSize == 8);
340 return Location::DoubleStackSlot(offset_in_words(), base_register_);
341 }
342#endif
343
344 virtual NativeStackLocation& Split(Zone* zone,
345 intptr_t num_parts,
346 intptr_t index) const;
347
348 virtual intptr_t StackTopInBytes() const {
350 }
351
352 virtual void PrintTo(BaseTextBuffer* f) const;
353
354 virtual bool Equals(const NativeLocation& other) const;
355
356 Register base_register() const { return base_register_; }
357 intptr_t offset_in_bytes() const { return offset_in_bytes_; }
358
359 private:
360 intptr_t offset_in_words() const {
361 ASSERT(offset_in_bytes_ % compiler::target::kWordSize == 0);
362 return offset_in_bytes_ / compiler::target::kWordSize;
363 }
364
365 Register base_register_;
366 intptr_t offset_in_bytes_;
367
368 DISALLOW_COPY_AND_ASSIGN(NativeStackLocation);
369};
370
371// The location of a pointer pointing to a compound.
372//
373// For arguments a pointer to a copy of an object. The backing copy of the
374// object typically resides on the stack.
375//
376// For return values a pointer to empty space that should hold the object. This
377// space also typically resides on the stack.
379 public:
381 const NativeCompoundType& object_pointed_to)
382 : NativeLocation(object_pointed_to, object_pointed_to),
383 pointer_location_(pointer_location),
384 pointer_return_location_(pointer_location) {
386 }
389 const NativeCompoundType& object_pointed_to)
390 : NativeLocation(object_pointed_to, object_pointed_to),
391 pointer_location_(pointer_location),
392 pointer_return_location_(pointer_return_location) {
394 }
395
397
398 virtual bool IsPointerToMemory() const { return true; }
399
400 virtual void PrintTo(BaseTextBuffer* f) const;
401
402 virtual bool Equals(const NativeLocation& other) const;
403
405 Zone* zone,
406 const NativeType& new_payload_type,
407 const NativeType& new_container_type) const {
409 }
410
411 virtual intptr_t StackTopInBytes() const {
413 }
414
415 // The location where the pointer is passed to the function.
416 const NativeLocation& pointer_location() const { return pointer_location_; }
417
418 // The location where the pointer is returned from the function.
420 return pointer_return_location_;
421 }
422
423 private:
424 const NativeLocation& pointer_location_;
425 // The return location is only in use for return values, not for arguments.
426 const NativeLocation& pointer_return_location_;
427
429};
430
432
433// A struct broken up over multiple native locations.
435 public:
440
441 virtual bool IsMultiple() const { return true; }
442
443 virtual void PrintTo(BaseTextBuffer* f) const;
444
446 Zone* zone,
447 const NativeType& new_payload_type,
448 const NativeType& new_container_type) const {
450 }
451
452 virtual intptr_t StackTopInBytes() const;
453
454 const NativeLocations& locations() const { return locations_; }
455
456 private:
457 const NativeLocations& locations_;
459};
460
461// The location of a value that is in two locations.
462//
463// Should only happen on win_x64 with variadic arguments.
465 public:
467 const NativeLocation& location1)
468 : NativeLocation(location0.payload_type(), location0.container_type()),
469 location0_(location0),
470 location1_(location1) {}
472
473 virtual bool IsBoth() const { return true; }
474
475 virtual void PrintTo(BaseTextBuffer* f) const;
476
478 Zone* zone,
479 const NativeType& new_payload_type,
480 const NativeType& new_container_type) const {
482 }
483
484 virtual intptr_t StackTopInBytes() const {
485 // Only used with registers.
486 return 0;
487 }
488
489 const NativeLocation& location(intptr_t index) const {
490 ASSERT(index == 0 || index == 1);
491 if (index == 0) {
492 return location0_;
493 }
494 return location1_;
495 }
496
497 private:
498 const NativeLocation& location0_;
499 const NativeLocation& location1_;
501};
502
503#if !defined(FFI_UNIT_TESTS)
504// Return a memory operand for stack slot locations.
506 const NativeStackLocation& loc);
507#endif
508
509} // namespace ffi
510
511} // namespace compiler
512
513} // namespace dart
514
515#endif // RUNTIME_VM_COMPILER_FFI_NATIVE_LOCATION_H_
void Add(const T &value)
const T & At(intptr_t index) const
intptr_t length() const
static Location FpuRegisterLocation(FpuRegister reg)
Definition locations.h:410
static Location DoubleStackSlot(intptr_t stack_index, Register base)
Definition locations.h:458
BothNativeLocations(const NativeLocation &location0, const NativeLocation &location1)
const NativeLocation & location(intptr_t index) const
virtual NativeLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
virtual void PrintTo(BaseTextBuffer *f) const
const NativeLocations & locations() const
virtual NativeLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
virtual void PrintTo(BaseTextBuffer *f) const
MultipleNativeLocations(const NativeCompoundType &payload_type, const NativeLocations &locations)
virtual NativeFpuRegistersLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
NativeFpuRegistersLocation(const NativeType &payload_type, const NativeType &container_type, FpuRegisterKind fpu_reg_kind, intptr_t fpu_register)
virtual bool Equals(const NativeLocation &other) const
virtual void PrintTo(BaseTextBuffer *f) const
NativeFpuRegistersLocation(const NativeType &payload_type, const NativeType &container_type, FpuRegister fpu_register)
NativeLocation & WidenTo8Bytes(Zone *zone) const
const MultipleNativeLocations & AsMultiple() const
virtual bool IsExpressibleAsLocation() const
virtual intptr_t StackTopInBytes() const
virtual Location AsLocation() const
const NativeType & container_type() const
virtual void PrintTo(BaseTextBuffer *f) const
const NativeRegistersLocation & AsRegisters() const
static bool LocationCanBeExpressed(Location loc, Representation rep)
const PointerToMemoryLocation & AsPointerToMemory() const
NativeLocation(const NativeType &payload_type, const NativeType &container_type)
virtual NativeLocation & Split(Zone *zone, intptr_t num_parts, intptr_t index) const
static NativeLocation & FromLocation(Zone *zone, Location loc, Representation rep)
const NativeStackLocation & AsStack() const
virtual NativeLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const =0
NativeLocation & WidenTo4Bytes(Zone *zone) const
static NativeLocation & FromPairLocation(Zone *zone, Location loc, Representation rep, intptr_t index)
const BothNativeLocations & AsBoth() const
virtual bool Equals(const NativeLocation &other) const
const NativeFpuRegistersLocation & AsFpuRegisters() const
const NativeType & payload_type() const
NativeRegistersLocation(const NativeType &payload_type, const NativeType &container_type, ZoneGrowableArray< Register > *registers)
virtual bool Equals(const NativeLocation &other) const
NativeRegistersLocation(Zone *zone, const NativeType &payload_type, const NativeType &container_type, Register register1, Register register2)
virtual NativeRegistersLocation & Split(Zone *zone, intptr_t num_parts, intptr_t index) const
virtual void PrintTo(BaseTextBuffer *f) const
NativeRegistersLocation(Zone *zone, const NativeType &payload_type, const NativeType &container_type, Register reg)
virtual NativeRegistersLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
virtual NativeStackLocation & Split(Zone *zone, intptr_t num_parts, intptr_t index) const
NativeStackLocation(const NativeType &payload_type, const NativeType &container_type, Register base_register, intptr_t offset_in_bytes)
virtual void PrintTo(BaseTextBuffer *f) const
virtual NativeStackLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
virtual bool Equals(const NativeLocation &other) const
virtual intptr_t SizeInBytes() const =0
PointerToMemoryLocation(const NativeLocation &pointer_location, const NativeLocation &pointer_return_location, const NativeCompoundType &object_pointed_to)
const NativeLocation & pointer_location() const
PointerToMemoryLocation(const NativeLocation &pointer_location, const NativeCompoundType &object_pointed_to)
virtual NativeLocation & WithOtherNativeType(Zone *zone, const NativeType &new_payload_type, const NativeType &new_container_type) const
virtual void PrintTo(BaseTextBuffer *f) const
virtual bool Equals(const NativeLocation &other) const
const NativeLocation & pointer_return_location() const
#define ASSERT(E)
intptr_t SizeFromFpuRegisterKind(enum FpuRegisterKind kind)
compiler::Address NativeLocationToStackSlotAddress(const NativeStackLocation &loc)
enum FpuRegisterKind FpuRegisterKindFromSize(intptr_t size_in_bytes)
ZoneGrowableArray< const NativeLocation * > NativeLocations
Representation
Definition locations.h:66
#define UNREACHABLE_THIS()
Definition native_type.h:25
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581