Commit Graph

94 Commits

Author SHA1 Message Date
Jake Hillion
213dba4325 oilgen: add to integration test framework
TODO: Replace the references to local paths.

oilgen (the basis of Ahead Of Time compilation for OIL) has never been passed
through our large test suite and has instead had more focused testing and large
examples. When consuming DWARF information in a similar fashion to JIT OIL this
was okay, but with the new Clang AST based mechanism it means we have very
little coverage.

This change adds an oilgen test for every test case that has an oil test.
Relying on the build system to create the test target as before would make it
difficult to have failing tests, so we move the build into the integration test
runner. This involves:
1. Writing the input source to a file.
2. Consuming it with oilgen to get the implementation object file.
3. Compiling the input source and linking it with this file.
4. Running the newly created target.

This approach can give the full error message at any stage that fails and will
fail the test appropriately. The downside is the build system integration is
more difficult, as we need the correct compiler flags for the target and to use
the correct compiler. It would be very tricky to replicate this in a build
system that's not CMake, so we will likely only run these tests in open source.

Test plan:
- CI
2024-01-04 11:53:19 +00:00
Jake Hillion
beb404e41c clangparser: mark incomplete arrays as incomplete without failing
Attempting to complete a type which can't be completed currently fails oilgen.
For incomplete arrays, which we know are not possible to complete, return false
deliberately.

`requireCompleteType` likely needs to not fail in all cases in the future. For
now this works.

Test plan:
- `std::unique_ptr<long[]>` used to fail the generation. Now it can
  successfully codegen.
2023-12-20 16:31:52 +00:00
Jake Hillion
c5ecb9aaa2 clangparser: provide alignment info for members
Unlike DWARF, the Clang AST is capable of correctly calculating the alignment
for each member. If we do this then AlignmentCalc doesn't traverse into the
member to attempt to calculate the alignment.

This check might be wrong if the field has explicit alignment. That case can be
covered when we have proper integration testing and a repro.

Test plan:
- Without this lots of static asserts occur. With this it's okay.
2023-12-20 16:15:12 +00:00
Jake Hillion
20cd48ac63 clangparser: provide correct kind for classes/unions
Previously ClangTypeParser assumed all RecordTypes were structs. This is fine
for structs and classes but completely incorrect for unions. Check which type
it is and give type graph the correct one.

Test plan:
- Unions static assert without this change because their size/alignment is
  wrong.
2023-12-20 16:15:02 +00:00
Jake Hillion
55989a9156 oilgen: migrate to source parsing (#421)
Summary:
oilgen: migrate to source parsing

Using debug information generated from partial source (that is, not the final
binary) has been insufficient to generally generate OIL code.

A particular example is pointers to templates:
```cpp
#include <oi/oi.h>
template <typename T>
struct Foo {
  T t;
};
template <typename T>
struct Bar {
  Foo<T>& f;
};
void foo(const Bar<int>& b) {
  oi::introspect(b);
}
```

The pointer/reference to `Foo<int>` appears in DWARF with
`DW_AT_declaration(true)` because it could be specialised before its usage.
However, with OIL, we are creating an implicit usage site in the
`oi::introspect` call that the compiler is unable to see.

This change reworks OILGen to work from a Clang command line rather than debug
information. We setup and run a compiler on the source, giving us access to an
AST and Semantic Analyser. We then:
- Find the `oi::introspect` template.
- Iterate through each of its callsites for their type.
- Run `ClangTypeParser::parse` on each type.
- Run codegen.
- Compile into an object file.

Having access to the semantic analyser allows us to forcefully complete a type,
as it would be if it was used in the initial code.


Test Plan:
hope

`buck2 run fbcode//mode/opt fbcode//object-introspection/oil/examples/compile-time:compile-time`

Reviewed By: tyroguru

Differential Revision: D51854477

Pulled By: JakeHillion
2023-12-19 13:26:25 -08:00
Alastair Robertson
2060a0491e CodeGen v2: Enable independent running without CodeGen v1
Create DrgnExporter to translate Type Graph "Type" nodes into drgn_type
structs, suitable for use in OICache and TreeBuilder.
2023-12-15 14:57:24 +00:00
Alastair Robertson
a0164e5cc7 TypeGraph: Make Class types use fully qualified names as their input names
This will ensure we continue to get fully qualified names in
user-visible output when we switch to CodeGen v2.
2023-12-15 14:45:01 +00:00
Alastair Robertson
688d483c0c TypeGraph: Fix handling for classes which inherit from containers
We previously moved container identification later in CodeGen in order
to preserve information for AlignmentCalc.

However, Flattener needs to know if a class is a container in order to
apply its special handling for this case.

This new approach moves container identification in front of Flattener,
but has Container own a type node, representing its layout. This
underlying type node can be used for calculating a container's
alignment in a later pass.
2023-12-14 18:02:45 +00:00
Alastair Robertson
aa87c3f2d1 NameGen: Override inputName for anonymous members 2023-12-14 17:42:48 +00:00
Alastair Robertson
8bf7dbae9f Type Graph: Replace MutationTracker with the more general ResultTracker
MutationTracker could only store Type nodes, while ResultTracker is
templated on the result type so can store anything.

Template the Visitor base class on the return type of visit() functions.

This sets us up for allowing visitors to return different results from
their visit() functions in the future.

This will be used in a future commit introducing DrgnExporter, where we
cache drgn_type* results while walking the type graph.
2023-12-14 13:43:19 +00:00
Alastair Robertson
7cc7aa8882 CodeGen: Remove Incomplete members from Classes
They must not appear in the final generated code as we'd end up with
invalid types with void members, e.g.:
  struct Foo {
    int a;
    void myIncompleteMember;
    int c;
  };

Removing them from the type graph early also ensures that padding is
calculated correctly.
2023-12-12 18:50:15 +00:00
Alastair Robertson
4fdf44b92d TypeGraph: Delete unused function in IdentifyContainers pass
It was accidentally copied from the TypeIdentifier pass.
2023-11-21 14:07:08 +00:00
Jake Hillion
25426127bb add range-v3 library
Adds the range-v3 library which supports features that otherwise wouldn't be
available until C++23 or C++26. I caught a couple of uses that suit it but this
will allow us to use more in future.

Test Plan:
- CI
2023-11-13 18:42:04 +00:00
Jake Hillion
393f8aab42 clang-format: disable bin packing
Bin packing often makes code hard to read. Disable it entirely.

Test plan:
- CI
2023-11-13 18:19:53 +00:00
Alastair Robertson
c207972af6 TypeGraph: Calculate alignment before identifying containers
Not all containers have 8-byte alignment, so if we want to avoid lots of
manual logic for calculating container alignment on a case-by-case
basis, we must calculate alignment from the member variables before the
Class nodes have been replaced by Container nodes.
2023-11-06 13:16:30 +00:00
Alastair Robertson
2c5fb5d845 TypeGraph: Stop identifying containers in DrgnParser
Leave it to the new mutator pass IdentifyContainers to replace Class
nodes with Container nodes where appropriate.

This will allow us to run passes over the type graph before identifying
containers, and therefore before we have lost information about the
internal details of the container (e.g. alignment of member variables).
2023-11-06 11:45:57 +00:00
Alastair Robertson
98008f9054 TypeGraph: Add IdentifyContainers mutator pass 2023-11-06 11:28:00 +00:00
Alastair Robertson
451678b19b TypeGraph: Create MutationTracker helper class 2023-11-06 11:28:00 +00:00
Alastair Robertson
30678b1dad TypeGraph: Create Mutator and RecursiveMutator base classes 2023-11-06 11:28:00 +00:00
Jake Hillion
6f623e95a4 incomplete: handle drgn returning a nullptr name 2023-10-30 16:47:50 +00:00
Alastair Robertson
e7581ad915 TopoSorter: Only allow certain params to be incomplete
For the containers which are allowed to be declared with incomplete
types, it is only the contained types which are allowed to be
incomplete. Other template parameters (e.g. allocators) must always be
defined before use.
2023-10-25 17:01:44 +01:00
Thierry Treyer
f4a1bd3d99 Remove Primitive::Kind::Incomplete 2023-10-04 11:23:28 -06:00
Thierry Treyer
3065dd14e9 Maintain type/name of Incomplete type 2023-10-04 11:23:28 -06:00
Alastair Robertson
3446339358 TypeGraph: Add KeyCapture pass 2023-09-28 19:42:49 -07:00
Alastair Robertson
0ae08addc9 TypeGraph: Add CaptureKeys node 2023-09-28 19:42:49 -07:00
Alastair Robertson
bd826f9794 CodeGen: Store list of ContainerInfos in unique_ptrs for reference stability
Lots of places rely on reference stability of ContainerInfo objects
(CodeGen's deduplication, Container nodes' containerInfo_ member).

In the key capture work, we need to be able to append to this list,
which would invalidate references before this change.
2023-09-22 17:10:56 +01:00
Jake Hillion
5632738d97 make StubbedPointer an explicit C++ type 2023-09-22 11:49:50 +01:00
Alastair Robertson
bbc4cb822b Printer: Make prefix() [[nodiscard]] and fix bug printing Dummy nodes
Dummy and DummyAllocator nodes had been changed to use NodeIds, but
were still printed out in full when visited for a second time.

[[nodiscard]] prevents future bugs of this type by turning them into
compilation errors.

Example of the now-fixed bug:
    [1]  Container: std::map<int32_t, int32_t, DummySizedOperator<0, 0, 8>, std::allocator<std::pair<int32_t const, int32_t>>>
            Param
              Primitive: int32_t
            Param
              Primitive: int32_t
            Param
    [2]       Dummy [less<int>]
            Param
              ...
    [3]   Container: std::map<int32_t, int32_t, DummySizedOperator<0, 0, 8>, std::allocator<std::pair<int32_t const, int32_t>>>
            Param
              Primitive: int32_t
            Param
              Primitive: int32_t
            Param
              [2]
    Dummy [less<int>]
            Param
              ...

With this patch, the second "Dummy" line will not be printed.
2023-09-21 17:01:35 +01:00
Alastair Robertson
a509354624 DrgnParser: Options should default to false
We only want to do the extra work if it's explicitly requested.

chaseRawPointers is already explicitly requested whenever it's needed
and readEnumValues currently isn't needed at all.
2023-09-19 18:32:37 +01:00
Jake Hillion
a6d74a20a6 Update to clang/llvm 15 (#342)
Summary:

Update to clang-15 compiler and libraries as clang-12 is ancient.

The changes to oilgen are necessary because the new internal toolchain is being more picky about linking PIC to PIC. In certain modes we build with PIC, but try to link a non-PIC oilgen artifact. Add the ability to build the oilgen artifacts with PIC which sorts this.

Reviewed By: ttreyer

Differential Revision: D46220858
2023-09-14 06:02:32 -07:00
Jake Hillion
d009f02ecb name contained types properly in treebuilder v2
Types within containers were previously named TODO. This sorts it out so
they're named as their most resolved type. The current implementation
skips Typedef names.
2023-08-25 16:25:14 +01:00
Alastair Robertson
03429f3da9 TypeGraph: Remove NodeTracker from the TypeGraph class
The TypeGraph class should only be responsible for storing Type nodes.
Traversing the graph and tracking which nodes have been visited should
not be included there.

Passes now take a NodeTrackerHolder as an input parameter, which
provides access to a zeroed-out NodeTracker.
2023-08-24 15:01:45 +01:00
Jake Hillion
5071519e45 oil v2 2023-08-23 15:59:53 +01:00
Jake Hillion
c62fbe371d type_graph: provide inputName for all types
Type Graph deduplicates and modifies names to better fit the generated
code, for example `int32_t[4]` becomes `OIArray<int32_t, 4>` and `struct
MyStruct` might become `struct MyStruct_0`.

Add an `inputName` which better represents the original input code which
can be used when building the tree.
2023-08-18 16:58:21 +01:00
Alastair Robertson
373dbe8f6c TypeGraph: Add option to record enumerator names 2023-08-17 15:47:23 +01:00
Jake Hillion
a2f7462a5d DrgnParser: store type of template param value 2023-08-17 15:40:34 +01:00
Alastair Robertson
ff31971bd3 Printer: Use NodeIds for stable IDs when printing graphs
This removes Printer's legacy behaviour of generating an ID for each
node as it gets printed. This old method meant that if new nodes were
added to or removed from a graph, every ID after the new/removed node
would change.

Now IDs are stable so it is easier to follow specific nodes through
multiple transformation passes in CodeGen.
2023-08-16 12:19:14 +01:00
Alastair Robertson
dca99fc4ad TypeGraph: Change Type::name() to return a reference instead of a copy
Names which were generated on-demand are now stored in member variables,
which are set during the ctor and can be regenerated when required (by
NameGen).
2023-08-15 15:33:21 +01:00
Alastair Robertson
57d2f3d380 DrgnParser: Don't error out for certain bad DWARF
Match the behaviour of CodeGen v1 and just log warnings when certain
debug info has issues.
2023-08-14 16:22:57 +01:00
Alastair Robertson
d45c7f4931 Flattener: Handle incomplete parent types 2023-08-02 14:29:19 +01:00
Alastair Robertson
0612159121 AlignmentCalc: Mark as packed if members are not aligned
We previously only marked as packed if there was no tail padding, which
was not a sufficient condition.

The new AlignmentCalcTest.PackedMembers test case is an example which
would previously not have been marked as packed.
2023-08-02 12:07:52 +01:00
Alastair Robertson
ececbe0a99 TopoSorter: Sort contained types after unique_ptr and shared_ptr
This is the same handling as regular pointers have. I came across a
type-cycle with unique_ptrs where this was necessary.
2023-08-01 17:53:39 +01:00
Alastair Robertson
e9975286b2 NameGen: Fix naming of const pointers 2023-08-01 17:53:39 +01:00
Alastair Robertson
6d30015764 TypeGraph: Set alignment for Thrift isset container to 1 2023-08-01 17:48:44 +01:00
Alastair Robertson
6fbb60826f
EnforceCompatibility: Stub out void pointers
CodeGen v1 does not record anything for pointers to incomplete types.
Not even the address, as is done for other pointers.

Introduce a new Primitive type "Incomplete". This behaves identically to
"Void", but allows us to tell whether a type was defined as void or if
it ended up like that because of incomplete DWARF information.
2023-07-31 14:28:05 +01:00
Alastair Robertson
7bb6791af9 AddPadding: Insert padding at the beginning of structs if necessary
This is sometimes needed now that we're removing members before adding
padding.
2023-07-27 16:01:35 +01:00
Jake Hillion
d7cfcca30d move all internal logic to oi::detail namespace 2023-07-26 18:01:38 +01:00
Alastair Robertson
e19641efad EnforceCompatibility: Follow OICodeGen's typesToStub list 2023-07-26 17:31:35 +01:00
Alastair Robertson
8b7bfbe4c0 TypeGraph: Add EnforceCompatibility pass
This extracts the compatibility logic from AddPadding, which allows for it to be
simplified and will make it easier to extend and eventually remove in the
future. No functional changes.
2023-07-26 17:12:36 +01:00
Alastair Robertson
45c3697f6b TypeGraph: Add Prune pass
This lets us remove fields from types when they are no longer needed,
speeding up later passes.

A secondary benefit of pruning unused types means that we sometimes
remove types for which we can't generate correct C++ code. This can
allow us to CodeGen for complex types which reference these broken types
without actually requiring them (e.g. as template parameters).

Add a new feature flag "prune-type-graph" to control this pass. It makes
sense to prune most of the time, but for testing CodeGen functionality
on a wider range of types, it will be useful to have the option to not
prune.
2023-07-26 16:56:34 +01:00