l4re-base-25.08.0

This commit is contained in:
2025-09-12 15:55:45 +02:00
commit d959eaab98
37938 changed files with 9382688 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
# scan the L4 global configuration file
L4DIR ?= ../../..
#include $(L4DIR)/mk/Makeconf
TOOL = ../src/preprocess
all:: test
ALL_TESTS = $(TOOL_TESTS)
TOOL_TESTS = mapping mapping_inline random random_inline extern_c static \
noinline explicit operator template template_inline c-preproc \
inline inline_noinline \
parser parser_noinline \
multifile variable line line_not line_nh interface comment_in_string \
default_args drop_single1 drop_single2 drop_single3 drop_multi1 \
drop_multi2 implement_template implement_default implement_default_err \
nested_class template_base_class func_defs extension_inherit \
tag_enabled
mapping_inline_src = mapping
mapping_inline_flags = -i
random_inline_src = random
random_inline_flags = -i
static_flags = -i
inline_flags = -i
inline_noinline_src = inline
inline_noinline_flags =
noinline_flags = -i
template_inline_src = template
template_inline_flags = -i
parser_flags = -i
parser_noinline_src = parser
parser_noinline_flags =
multifile_src = multifile1 multifile2
multifile_flags = -i
multifile_extra = multifile-part1.cc multifile-part2.cc
line_not_src = line
line_not_flags = -l
line_nh_src = line
line_nh_flags = -L
interface_missing = interface.h
interface_extra = interfacepublic.h
drop_single1_src = dropsection
drop_single1_flags = -s -e "bax"
drop_single2_src = dropsection
drop_single2_flags = -s -e "bax ixbix"
drop_single3_src = dropsection
drop_single3_flags = -s -e "bax aba"
drop_multi1_src = dropsection dropsection-ext
drop_multi1_flags = -s -e "bax aba"
drop_multi1_extra = drop_multi1-ext.cc
drop_multi2_src = dropsection dropsection-ext
drop_multi2_flags = -s -e "bax aba ext"
drop_multi2_extra = drop_multi2-ext.cc
ifdef_src = ifdef
ifdef_flags = -s -e "true"
ifdef1_src = ifdef1
ifdef1_flags = -s -e "true"
ifdef1_extra = ifdef1-more.cpp
implement_default_redirect = 2>implement_default.stderr
implement_default_extra = implement_default.stderr
implement_default_err_redirect = 2>implement_default_err.stderr; test $$? -ne 0
implement_default_err_extra = implement_default_err.stderr
implement_default_err_missing += implement_default_err.h
implement_default_err_missing += implement_default_err_i.h
implement_default_err_missing += implement_default_err.cc
tag_enabled_src = tag_enabled
tag_enabled_flags = -e tag_defined
random.cpp: combine.pl
perl $< > $@.new
mv $@.new $@
clean::
rm -f random.cpp
test_rules: Makefile
rm -f $@.new
for test in $(TOOL_TESTS); \
do \
echo "ifndef $${test}_src" >> $@.new; \
echo "$${test}_src = $${test}" >> $@.new; \
echo "endif" >> $@.new; \
echo "ifndef $${test}_flags" >> $@.new; \
echo "$${test}_flags = " >> $@.new; \
echo "endif" >> $@.new; \
echo "ifndef $${test}_redirect" >> $@.new; \
echo "$${test}_redirect = " >> $@.new;\
echo "endif" >> $@.new; \
echo "$${test}.cc: \$$(addsuffix .cpp, \$$($${test}_src)) \$$(TOOL); \$$(TOOL) \$$($${test}_flags) -c $${test} \$$(filter-out \$$(TOOL), \$$^) \$$($${test}_redirect)" >> $@.new; \
echo "ifdef $${test}_extra" >> $@.new; \
echo "clean:: ; \$$(RM) \$$($${test}_extra)" >> $@.new; \
echo "endif" >> $@.new; \
done
mv $@.new $@
include test_rules
clean::
rm -f $(addsuffix .cc, $(TOOL_TESTS)) \
$(addsuffix .h, $(TOOL_TESTS)) \
$(addsuffix _i.h, $(TOOL_TESTS))
.PHONY: test
test: $(addsuffix .t.ok, $(ALL_TESTS))
%.t.ok: %.cc
@echo -n "Running test $* ... "
ifeq ($(RECREATE_OUTPUT),1)
@cp $(filter-out $($*_missing),$*.h $*_i.h $*.cc) $($*_extra) verify/
endif
@ERROR=0; \
for i in $(filter-out $($*_missing),$*.h $*_i.h $*.cc) $($*_extra); \
do \
if ! diff --color -u verify $$i; then ERROR=1; fi; \
done; \
test $$ERROR -eq 0
@echo "OK"
@touch $@
.PHONY: init
init:
$(MAKE) test RECREATE_OUTPUT=1
install:
@echo Not installing tests.
clean::
$(RM) $(ALL) $(OBJS) *.t.ok
cleanall:: clean
$(RM) *~ .*.d test_rules
#include $(DEPS)

View File

@@ -0,0 +1,19 @@
INTERFACE:
IMPLEMENTATION:
// set CS (missing from OSKIT)
#define set_cs(cs) \
asm volatile \
("ljmp %0,$1f \n1:" \
: : "i" (cs));
void
function (void)
{
#if 1
bar ();
#else
foo ();
#endif
}

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env perl
use warnings;
print '
INTERFACE:
#include "bar.h"
class Baz;
class Foo : public Bar
{
// DATA
int d_data;
Baz* d_baz;
};
IMPLEMENTATION:
#include "yes.h"
#include <no.h>
class Rambo
{
};
// Try combinations of {PUBLIC|PROTECTED|PRIVATE|} {static|}
// {inline|INLINE|inline NEEDS[]|INLINE NEEDS[]} {virtual|}
';
$count = 0;
foreach my $class ("Foo", "")
{
foreach my $public ("PUBLIC", "PROTECTED", "PRIVATE", "")
{
foreach my $static ("static", "")
{
foreach my $inline ("inline", "INLINE",
"inline NEEDS [Rambo,\"yes.h\"]",
"INLINE NEEDS[Rambo, \"yes.h\"]", "")
{
foreach my $virtual ("virtual", "")
{
next if ($public ne '') && ($class eq '');
next if ($virtual ne '') && (($static ne '')
|| ($class eq ''));
print "$public $virtual $static $inline\n";
print "void ";
print "${class}::" if ($class ne '');
print "function" . $count++;
print "() {}\n\n";
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
INTERFACE:
IMPLEMENTATION:
int foo(char *s);
void irq_init(unsigned char master_base, unsigned char slave_base)
{
if (!(foo(" -vmware"))
{
foo("outb_p(MASTER_OCW, 0xfb); // unmask irq2");
}
else
{
foo("using normal pic mode \n");
}
}
void bar()
{
foo ("if (0) {");
foo ("} // if(0)");
}

View File

@@ -0,0 +1,32 @@
#include <vector>
IMPLEMENTATION:
template <typename T>
std::vector<T>
vec(T f1 = T(), T f2 = T(), T f3 = T(),
T f4 = T(), T f5 = T(), T f6 = T())
{
std::vector<T> v;
if (f1 != T()) {
v.push_back (f1);
if (f2 != T()) {
v.push_back (f2);
if (f3 != T()) {
v.push_back (f3);
if (f4 != T()) {
v.push_back (f4);
if (f5 != T()) {
v.push_back (f5);
if (f6 != T()) {
v.push_back (f6);
}}}}}}
return v;
}
extern "C"
void
disasm_bytes(char *buffer, unsigned len, unsigned va, unsigned task,
int show_symbols, int show_intel_syntax,
int (*peek_task)(unsigned addr, unsigned task),
const char* (*get_symbol)(unsigned addr, unsigned task)) WEAK;

View File

@@ -0,0 +1,26 @@
INTERFACE [ext]:
/**
* Preprocess should discard this comment and adjust the line directive
* accordingly.
*/
EXTENSION class Gen_foo : public Gen_bar
{
public:
int extra_var;
};
EXTENSION class Gen_foo_ext : public Gen_baz
{
private:
char *extension;
};
IMPLEMENTATION [ext]:
PRIVATE int
Gen_foo::do_something_private()
{
// just do it
}

View File

@@ -0,0 +1,60 @@
INTERFACE:
class Gen_foo
{
public:
int baz;
protected:
int foo( int );
};
class Gen_foo_ext : private Gen_foo, public Ixdebix
{
protected:
unsigned stuff;
};
IMPLEMENTATION:
PUBLIC inline void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
PUBLIC void
Gen_foo_ext::test()
{
// the test
}
IMPLEMENTATION [ixbix-bax]:
IMPLEMENT int
Gen_foo::foo( int y )
{
// do something strange with y
bar(y);
return y;
}
IMPLEMENTATION [aba-bax]:
IMPLEMENT int
Gen_foo::foo( int y )
{
// just return y
return y;
}
IMPLEMENTATION [{!bax,!ixbix}]:
PUBLIC int
Gen_foo::tust( int y )
{
// just return y
return y;
}

View File

@@ -0,0 +1,11 @@
INTERFACE:
class Foo
{
};
IMPLEMENTATION:
PUBLIC explicit
Foo::Foo (int bar)
{}

View File

@@ -0,0 +1,155 @@
INTERFACE:
// Variable number of class inheritance extensions
class Class_b0_e1
{
};
EXTENSION class Class_b0_e1 : Ext_base_0
{
};
// ----------------------------------------------------------------------
class Class_b0_e1_e1
{
};
EXTENSION class Class_b0_e1_e1 : Ext_base_0
{
};
EXTENSION class Class_b0_e1_e1 : Ext2_base_0
{
};
// ----------------------------------------------------------------------
class Class_b0_e2
{
};
EXTENSION class Class_b0_e2 : Ext_base_0, Ext_base_1
{
};
// ----------------------------------------------------------------------
class Class_b0_e2_e1
{
};
EXTENSION class Class_b0_e2_e1 : Ext_base_0, Ext_base_1
{
};
EXTENSION class Class_b0_e2_e1 : Ext2_base_0
{
};
// ----------------------------------------------------------------------
class Class_b1_e1 : Base_0
{
};
EXTENSION class Class_b1_e1 : Ext_base_0
{
};
// ----------------------------------------------------------------------
class Class_b1_e1_e1 : Base_0
{
};
EXTENSION class Class_b1_e1_e1 : Ext_base_0
{
};
EXTENSION class Class_b1_e1_e1 : Ext2_base_0
{
};
// ----------------------------------------------------------------------
class Class_b1_e2 : Base_0
{
};
EXTENSION class Class_b1_e2 : Ext_base_0, Ext_base_1
{
};
// ----------------------------------------------------------------------
class Class_b1_e2_e1 : Base_0
{
};
EXTENSION class Class_b1_e2_e1 : Ext_base_0, Ext_base_1
{
};
EXTENSION class Class_b1_e2_e1 : Ext2_base_0
{
};
// ----------------------------------------------------------------------
class Class_b2_e1 : Base_0, Base_1
{
};
EXTENSION class Class_b2_e1 : Ext_base_0
{
};
// ----------------------------------------------------------------------
class Class_b2_e1_e1 : Base_0, Base_1
{
};
EXTENSION class Class_b2_e1_e1 : Ext_base_0
{
};
EXTENSION class Class_b2_e1_e1 : Ext2_base_0
{
};
// ----------------------------------------------------------------------
class Class_b2_e2 : Base_0, Base_1
{
};
EXTENSION class Class_b2_e2 : Ext_base_0, Ext_base_1
{
};
// ----------------------------------------------------------------------
class Class_b2_e2_e1 : Base_0, Base_1
{
};
EXTENSION class Class_b2_e2_e1 : Ext_base_0, Ext_base_1
{
};
EXTENSION class Class_b2_e2_e1 : Ext2_base_0
{
};
// Variable spacing around class inheritance extensions
class Class_var : Base_0 /* Unconvenient comment
that wraps around */ {
};
EXTENSION class Class_var
: Ext_base_0
{
};
EXTENSION class Class_var : Ext2_base_0
{
};
EXTENSION class Class_var : Ext3_base_0 {};
IMPLEMENTATION:

View File

@@ -0,0 +1,8 @@
INTERFACE:
IMPLEMENTATION:
extern "C"
{
extern char _mappings_1, _mappings_end_1;
}

View File

@@ -0,0 +1,60 @@
INTERFACE:
class Test
{
};
IMPLEMENTATION:
PUBLIC
void
Test::func1() const throw()
{}
PUBLIC
void
Test::func2() throw(int, char const *) override final
{};
PUBLIC
void
Test::func3(unsigned) noexcept final override
{}
PUBLIC
void
Test::func4(int) noexcept ( this->func2() )
{}
PUBLIC explicit
Test::Test(int) noexcept(true) __attribute__ (( test("str") )) final
: init(This)
{}
PUBLIC
void
Test::func5() noexcept ( this->func2() ) [[test(attr)]] [[test2]]
{}
PUBLIC [[cppattr]] [[another_attr]] static inline
int
Test::func_attr_no_needs()
{}
PUBLIC [[anattr]] inline NEEDS["bar_fails"]
int
Test::func_attr_needs()
{}
PUBLIC inline
int attribute((foo("murx("))) [[this->is->a->test]]
Test::func_with_stupid_attributes(Tmpl<Type> x) const && throw() = default;
/**
* This is the comment for `free_function`.
*/
Test const &
free_function(int, long a) noexcept
{
return Test(a);
}

View File

@@ -0,0 +1,33 @@
INTERFACE:
class Test
{
public:
void warn_func1();
void warn_func2();
void func1();
void func2();
void defl();
// skip this as the test cannot deal with errors
// void err_func1();
};
IMPLEMENTATION:
IMPLEMENT_DEFAULT void Test::warn_func1() { /* this is the default */ }
IMPLEMENT void Test::warn_func1() { /* this is the override */ }
IMPLEMENT void Test::warn_func2() { /* this is the override */ }
IMPLEMENT_DEFAULT void Test::warn_func2() { /* this is the default */ }
IMPLEMENT_DEFAULT void Test::func1() { /* this is the default */ }
IMPLEMENT_OVERRIDE void Test::func1() { /* this is the override */ }
IMPLEMENT_OVERRIDE void Test::func2() { /* this is the override */ }
IMPLEMENT_DEFAULT void Test::func2() { /* this is the default */ }
IMPLEMENT_DEFAULT void Test::defl() { /* this is the default */ }
// skip this as the test cannot deal with errors
// IMPLEMENT_OVERRIDE void Test::err_func1() { /* this is the override */ }

View File

@@ -0,0 +1,11 @@
INTERFACE:
class Test
{
public:
void err_func1();
};
IMPLEMENTATION:
IMPLEMENT_OVERRIDE void Test::err_func1() { /* this is the override */ }

View File

@@ -0,0 +1,31 @@
INTERFACE:
template< typename T >
class Test
{
public:
void test_func();
};
IMPLEMENTATION:
IMPLEMENT
template< typename T >
// comment
void __attribute__((deprecated))
Test<T>::test_func()
{
}
PUBLIC
template< typename T > // comment 1
template<
typename X, // comment within template args list
typename X2 // another comment in tl args
>
// comment 2
void __attribute__((deprecated))
Test<T>::test_func2<X, X2>()
{
}

View File

@@ -0,0 +1,112 @@
INTERFACE:
class Foo
{
};
class Bar
{
};
class Cexpr
{
constexpr test1();
};
IMPLEMENTATION:
// Test dependency-chain resolver
class Frob
{
};
inline
bool
Frob::private_func()
{
}
inline
bool
Foo::private_func()
{
}
inline
bool
Bar::private_func()
{
}
constexpr
bool
Frob::private_cexpr()
{
}
inline NEEDS [Foo::private_func, Bar::private_func]
void
Bar::another_private_func()
{
}
PUBLIC inline NEEDS [Bar::another_private_func, Frob::private_func]
void
Bar::public_func()
{
}
// This inline funtion is public only because it is needed by an
// extern-"C" function. So we do not want to export it.
PUBLIC inline NOEXPORT
void
Foo::bar()
{
}
// Try both NOEXPORT and NEEDED.
PUBLIC inline NOEXPORT NEEDS[Foo::private_func]
void
Foo::baz()
{
}
PUBLIC constexpr NEEDS[Foo::private_func]
void
Foo::cexpr1()
{
}
PUBLIC constexpr NOEXPORT
void
Foo::cexpr2()
{
}
IMPLEMENT constexpr
void
Cexpr::test1()
{
}
IMPLEMENT inline constexpr
void
Cexpr::test2()
{
}
extern "C"
void function (Foo* f)
{
f->bar();
f->cexpr2();
}
template <typename T> inline void* xcast(T* t)
{
return (void*) t;
}

View File

@@ -0,0 +1,15 @@
INTERFACE [interfacepublic]:
// This is class Foo.
class Foo
{
};
IMPLEMENTATION:
PUBLIC
void
Foo::func1()
{
}

View File

@@ -0,0 +1,20 @@
INTERFACE:
// This is class Foo.
class Foo
{
};
IMPLEMENTATION:
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
PUBLIC
inline
static
void
Foo::func1()
{
}

View File

@@ -0,0 +1,784 @@
INTERFACE:
#include <flux/x86/types.h> // for vm_offset_t, vm_size_t
#include "space.h" // for space_index_t
enum mapping_type_t { Map_mem = 0, Map_io };
class mapping_tree_t; // forward decls
struct mapping_s;
//
// class mapping_t
//
class mapping_t
{
friend class mapdb_t;
friend class mapping_tree_t;
friend class jdb;
// CREATORS
mapping_t(const mapping_t&); // this constructor is undefined.
// DATA
char _data[5];
} __attribute__((packed));
class kmem_slab_t;
struct physframe_data;
//
// class mapdb_t: The mapping database
//
class mapdb_t
{
friend class jdb;
public:
enum { Size_factor = 4,
Size_id_max = 8 /* can be up to 15 (4 bits) */ };
private:
// DATA
physframe_data *physframe;
kmem_slab_t *allocator_for_treesize[Size_id_max + 1];
};
IMPLEMENTATION:
// The mapping database.
// This implementation encodes mapping trees in very compact arrays of
// fixed sizes, prefixed by a tree header (mapping_tree_t). Array
// sizes can vary from 4 mappings to 4<<15 mappings. For each size,
// we set up a slab allocator. To grow or shrink the size of an
// array, we have to allocate a larger or smaller tree from the
// corresponding allocator and then copy the array elements.
//
// The array elements (mapping_t) contain a tree depth element. This
// depth and the relative position in the array is all information we
// need to derive tree structure information. Here is an example:
//
// array
// element depth
// number value comment
// --------------------------
// 0 0 Sigma0 mapping
// 1 1 child of element #0 with depth 0
// 2 2 child of element #1 with depth 1
// 3 2 child of element #1 with depth 1
// 4 3 child of element #3 with depth 2
// 5 2 child of element #1 with depth 1
// 6 3 child of element #5 with depth 2
// 7 1 child of element #0 with depth 0
//
// This array is a pre-order encoding of the following tree:
//
// 0
// / \
// 1 7
// / | \
// 2 3 5
// | |
// 4 6
// IDEAS for enhancing this implementation:
// We often have to find a tree header corresponding to a mapping.
// Currently, we do this by iterating backwards over the array
// containing the mappings until we find the Sigma0 mapping, from
// whose address we can compute the address of the tree header. If
// this becomes a problem, we could add one more byte to the mappings
// with a hint (negative array offset) where to find the sigma0
// mapping. (If the hint value overflows, just iterate using the hint
// value of the mapping we find with the first hint value.) Another
// idea (from Adam) would be to just look up the tree header by using
// the physical address from the page-table lookup, but we would need
// to change the interface of the mapping database for that (pass in
// the physical address at all times), or we would have to include the
// physical address (or just the address of the tree header) in the
// mapdb_t-user-visible mapping_t (which could be different from the
// internal tree representation). (XXX: Implementing one of these
// ideas is probably worthwile doing!)
// Instead of copying whole trees around when they grow or shrink a
// lot, or copying parts of trees when inserting an element, we could
// give up the array representation and add a "next" pointer to the
// elements -- that is, keep the tree of mappings in a
// pre-order-encoded singly-linked list (credits to: Christan Szmajda
// and Adam Wiggins). 24 bits would probably be enough to encode that
// pointer. Disadvantages: Mapping entries would be larger, and the
// cache-friendly space-locality of tree entries would be lost.
// The current handling of superpages sucks rocks both in this module
// and in our user, ipc_map.cc. We could support multiple page sizes
// by not using a physframe[] array only for the largest page size.
// (Entries of that array point to the top-level mappings -- sigma0
// mappings.) Mapping-tree entries would then either be regular
// mappings or pointers to an array of mappings of the next-smaller
// size. (credits: Christan Szmajda)
//
// physframe[]
// -------------------------------
// | | | | | | | | | | | | | | | | array of ptr to 4M mapping_tree_t's
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t *or* ptr to array of ptr to 4K trees
// | | e.g.
// | ----------------|
// | | v array of ptr to 4M mapping_tree_t's
// --------------- -------------------------------
// | | | | | | | | | | | | | | | |
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t
// | |
// | |
// | |
// ---------------
//-
#include <assert.h>
#include <string.h>
#ifndef offsetof // should be defined in stddef.h, but isn't
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
// For implementation of mapping_t functions, we need mapping_tree_t.
//
// class mapping_tree_t
//
class mapping_tree_t
{
friend class mapping_t;
friend class mapdb_t;
friend class jdb;
// DATA
unsigned _count: 16;
unsigned _size_id: 4;
unsigned _empty_count: 11;
unsigned _unused: 1; // make this 32 bits to avoid a compiler bug
mapping_t _mappings[0] __attribute__((packed));
} __attribute__((packed));
// public routines with inline implementations
inline
unsigned
mapping_tree_t::number_of_entries() const
{
return mapdb_t::Size_factor << _size_id;
}
inline
mapping_t *
mapping_tree_t::mappings()
{
return & _mappings[0];
}
// Define (otherwise private) stuff needed by public inline
// functions.
enum mapping_depth_t
{
Depth_sigma0_mapping = 0, Depth_max = 253,
Depth_empty = 254, Depth_end = 255
};
struct mapping_s
{
unsigned space:11;
unsigned size:1;
unsigned address:20;
mapping_depth_t depth:8;
unsigned do_not_touch: 24; // make this 64 bits, and make sure the
// compiler never touches memory after the
// real data
};
inline
mapping_t::mapping_t()
{}
inline
mapping_s *
mapping_t::data()
{
return reinterpret_cast<mapping_s*>(_data);
}
PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
space_index_t
mapping_t::space()
{
return space_index_t(data()->space);
}
PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
vm_offset_t
mapping_t::vaddr()
{
return (data()->address << PAGE_SHIFT);
}
PUBLIC inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
vm_size_t
mapping_t::size()
{
if ( data()->size )
return SUPERPAGE_SIZE;
else
return PAGE_SIZE;
}
PUBLIC inline
mapping_type_t
mapping_t::type()
{
// return data()->type;;
return Map_mem;
}
inline NEEDS[mapping_depth_t, mapping_s, mapping_t::data]
bool
mapping_t::unused()
{
return (data()->depth > Depth_max);
}
mapping_tree_t *
mapping_t::tree()
{
mapping_t *m = this;
while (m->data()->depth > Depth_sigma0_mapping)
{
// jump in bigger steps if this is not a free mapping
if (! m->unused())
{
m -= m->data()->depth;
continue;
}
m--;
}
return reinterpret_cast<mapping_tree_t *>
(reinterpret_cast<char *>(m) - offsetof(mapping_tree_t, _mappings));
}
//
// more of class mapping_t
//
PUBLIC mapping_t *
mapping_t::parent()
{
if (data()->depth <= Depth_sigma0_mapping)
{
// Sigma0 mappings don't have a parent.
return nullptr;
}
// Iterate over mapping entries of this tree backwards until we find
// an entry with a depth smaller than ours. (We assume here that
// "special" depths (empty, end) are larger than Depth_max.)
mapping_t *m = this - 1;
while (m->data()->depth >= data()->depth)
m--;
return m;
}
PUBLIC mapping_t *
mapping_t::next_iter()
{
mapping_tree_t *t = tree();
mapping_t *last_in_tree = t->mappings() + t->number_of_entries() - 1;
mapping_t *m = this;
// Look for a valid element in the tree structure.
while (m != last_in_tree)
{
m++;
if (! m->unused())
return m; // Found a valid entry!
// Don't iterate to end of tree if this is the last tree entry.
if (m->data()->depth == Depth_end)
return 0;
}
// Couldn't find a non-empty element behind ourselves in the tree
// structure.
return 0;
}
PUBLIC mapping_t *
mapping_t::next_child(mapping_t *parent)
{
// Find the next valid entry in the tree structure.
mapping_t *m = next_iter();
// If we didn't find an entry, or if the entry cannot be a child of
// "parent", return nullptr
if (m == 0
|| m->data()->depth <= parent->data()->depth)
return nullptr;
return m; // Found!
}
// helpers
//
// class mapping_tree_t
//
// This function copies the elements of mapping tree src to mapping
// tree dst, ignoring empty elements (that is, compressing the
// source tree. In-place compression is supported.
PUBLIC static void
mapping_tree_t::copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src)
{
dst->_count = 0;
dst->_empty_count = 0;
mapping_t *d = dst->mappings();
for (mapping_t *s = src->mappings();
s < src->mappings() + src->number_of_entries();
s++)
{
if (s->unused()) // entry free
{
if (s->data()->depth == Depth_end)
break;
continue;
}
*d++ = *s;
dst->_count += 1;
}
assert (dst->_count == src->_count);
assert (d < dst->mappings() + dst->number_of_entries());
d->data()->depth = Depth_end;
dst->mappings()[dst->number_of_entries() - 1].data()->depth = Depth_end;
} // copy_compact_tree()
//
// class mapdb
//
#include "lock.h"
#include "kmem_slab.h"
struct physframe_data {
mapping_tree_t *tree;
helping_lock_t lock;
};
PUBLIC
mapdb_t::mapdb_t()
{
vm_offset_t page_number = kmem::info()->main_memory.high / PAGE_SIZE + 1;
// allocate physframe array
check ( physframe = reinterpret_cast<physframe_data *>
(kmem::alloc(page_number * sizeof(physframe_data))) );
memset(physframe, 0, page_number * sizeof(physframe_data));
// create a slab for each mapping tree size
for (int slab_number = 0;
slab_number <= Size_id_max;
slab_number++ )
{
unsigned elem_size =
(Size_factor << slab_number) * sizeof(mapping_t)
+ sizeof(mapping_tree_t);
allocator_for_treesize[slab_number] =
new kmem_slab_t(((PAGE_SIZE / elem_size) < 40
? 8*PAGE_SIZE : PAGE_SIZE),
elem_size, 1);
}
// create a sigma0 mapping for all physical pages
for (unsigned page_id = 0; page_id < page_number; page_id++)
{
mapping_tree_t *t;
check( (t = physframe[page_id].tree
= reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[0]->alloc())) );
t->_count = 1; // 1 valid mapping
t->_size_id = 0; // size is equal to Size_factor << 0
t->_empty_count = 0; // no gaps in tree representation
t->mappings()[0].data()->depth = Depth_sigma0_mapping;
t->mappings()[0].data()->address = page_id;
t->mappings()[0].data()->space = config::sigma0_taskno;
t->mappings()[0].data()->size = 0;
t->mappings()[1].data()->depth = Depth_end;
// We also always set the end tag on last entry so that we can
// check whether it has been overwritten.
t->mappings()[t->number_of_entries() - 1].data()->depth = Depth_end;
}
} // mapdb_t()
// insert a new mapping entry with the given values as child of
// "parent" After locating the right place for the new entry, it will
// be stored there (if this place is empty) or the following entries
// moved by one entry.
// We assume that there is at least one free entry at the end of the
// array so that at least one insert() operation can succeed between a
// lock()/free() pair of calls. This is guaranteed by the free()
// operation which allocates a larger tree if the current one becomes
// to small.
PUBLIC mapping_t *
mapdb_t::insert(mapping_t *parent,
space_t *space,
vm_offset_t va,
vm_size_t size,
mapping_type_t type)
{
assert(type == Map_mem); // we don't yet support Map_io
mapping_tree_t *t = parent->tree();
// We cannot continue if the last array entry is not free. This
// only happens if an earlier call to free() with this mapping tree
// couldn't allocate a bigger array. In this case, signal an
// out-of-memory condition.
if (! t->mappings()[t->number_of_entries() - 1].unused())
return nullptr;
// If the parent mapping already has the maximum depth, we cannot
// insert a child.
if (parent->data()->depth == Depth_max)
return nullptr;
mapping_t *insert = 0;
bool
found_free_entry = false,
need_to_move = false;
mapping_t temp;
// Find a free entry in the array encoding the tree, and find the
// insertion point for the new entry. These two entries might not
// be equivalent, so we may need to move entries backwards in the
// array. In this implementation, we move entries as we traverse
// the array, instead of doing one big memmove
for (mapping_t *m = parent + 1;
m < t->mappings() + t->number_of_entries();
m++)
{
if (m->unused())
{
// We found a free entry in the tree -- allocate it.
found_free_entry = true;
t->_count += 1;
// Did we find an empty element != the end tag?
if (m->data()->depth == Depth_empty)
{
t->_empty_count -= 1;
}
// Else we have found the end tag. If there is another
// array entry left, apply a new end tag to the array
else if (m + 1 < t->mappings() + t->number_of_entries())
{
(m + 1)->data()->depth = Depth_end;
}
// if we haven't identified a place for inserting the new
// element, this is it.
if (! need_to_move)
insert = m;
}
else if (! need_to_move
&& m->data()->depth <= parent->data()->depth)
{
// we found a non-descendant of ourselves -- need to make
// space for new child
need_to_move = true;
insert = m;
temp = *insert;
continue;
}
if (need_to_move)
{
// replace *m with temp (which used to be *(m - 1); but
// *(m - 1) has since been overwritten), and load temp with
// the old value of *m
mapping_t temp2;
temp2 = *m;
*m = temp;
temp = temp2;
}
if (found_free_entry)
break;
}
assert(insert && found_free_entry);
// found a place to insert new child.
insert->data()->depth = mapping_depth_t(parent->data()->depth + 1);
insert->data()->address = va >> PAGE_SHIFT;
insert->data()->space = space->space();
insert->data()->size = (size == SUPERPAGE_SIZE);
return insert;
} // insert()
PUBLIC mapping_t *
mapdb_t::lookup(space_t *space,
vm_offset_t va,
mapping_type_t type)
{
vm_offset_t phys = space->virt_to_phys(va);
if (phys == 0xffffffff)
return nullptr;
mapping_tree_t *t;
// get and lock the tree.
// XXX For now, use a simple lock with helping. Later
// unify locking with our request scheme.
physframe[phys >> PAGE_SHIFT].lock.lock();
t = physframe[phys >> PAGE_SHIFT].tree;
assert(t);
mapping_t *m;
for (m = t->mappings();
m->data()->depth != Depth_end
&& m < t->mappings() + t->number_of_entries();
m++)
{
if (m->data()->space == space->space()
&& m->data()->address == va >> PAGE_SHIFT)
{
// found!
return m;
}
}
// not found -- unlock tree
physframe[phys >> PAGE_SHIFT].lock.clear();
return nullptr;
} // lookup()
PUBLIC void
mapdb_t::free(mapping_t* mapping_of_tree)
{
mapping_tree_t *t = mapping_of_tree->tree();
// We assume that the zeroth mapping of the tree is a sigma0
// mapping, that is, its virtual address == the page's physical
// address.
vm_offset_t phys_pno = t->mappings()[0].data()->address;
// We are the owner of the tree lock.
assert(physframe[phys_pno].lock.lock_owner() == current());
// Before we unlock the tree, we need to make sure that there is
// room for at least one new mapping. In particular, this means
// that the last entry of the array encoding the tree must be free.
// (1) When we use up less than a quarter of all entries of the
// array encoding the tree, copy to a smaller tree. Otherwise, (2)
// if the last entry is free, do nothing. Otherwise, (3) if less
// than 3/4 of the entries are used, compress the tree. Otherwise,
// (4) copy to a larger tree.
bool maybe_out_of_memory = false;
do // (this is not actually a loop, just a block we can "break" out of)
{
// (1) Do we need to allocate a smaller tree?
if (t->_size_id > 0 // must not be smallest size
&& (t->_count << 2) < t->number_of_entries())
{
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t *>
(allocator_for_treesize[t->_size_id - 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id - 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
break;
}
}
// (2) Is last entry is free?
if (t->mappings()[t->number_of_entries() - 1].unused())
break; // OK, last entry is free.
// Last entry is not free -- either compress current array
// (i.e., move free entries to end of array), or allocate bigger
// array.
// (3) Should we compress the tree?
// We also try to compress if we cannot allocate a bigger
// tree because there is no bigger tree size.
if (t->_count < (t->number_of_entries() >> 2)
+ (t->number_of_entries() >> 1)
|| t->_size_id == Size_id_max) // cannot enlarge?
{
if (t->_size_id == Size_id_max)
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
break;
}
// (4) OK, allocate a bigger array.
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[t->_size_id + 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id + 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
}
else
{
// out of memory -- just do tree compression and hope that helps.
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
}
}
while (false);
// The last entry of the tree should now be free -- exept if we're
// out of memory.
assert(t->mappings()[t->number_of_entries() - 1].unused()
|| maybe_out_of_memory);
// Unlock tree.
physframe[phys_pno].lock.clear();
} // free()
// Delete mappings from a tree. This is easy to do: We just have to
// iterate over the array encoding the tree.
PUBLIC bool
mapdb_t::flush(mapping_t *m, bool me_too)
{
mapping_tree_t *t = m->tree();
mapping_t *start_of_deletions = m;
unsigned m_depth = m->data()->depth;
unsigned deleted = 0, empty_elems_passed = 0;
if (me_too)
{
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
else
start_of_deletions++;
m++;
for (;
m < t->mappings() + t->number_of_entries()
&& m->data()->depth != Depth_end;
m++)
{
if (unsigned (m->data()->depth) <= m_depth)
{
// Found another data element -- stop deleting. Since we
// created holes in the tree representation, account for it.
t->_empty_count += deleted;
return true;
}
if (m->data()->depth == Depth_empty)
{
empty_elems_passed++;
continue;
}
// Delete the element.
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
// We deleted stuff at the end of the array -- move end tag
if (start_of_deletions < t->mappings() + t->number_of_entries())
{
start_of_deletions->data()->depth = Depth_end;
// also, reduce number of free entries
t->_empty_count -= empty_elems_passed;
}
return true;
} // flush()
PUBLIC void
mapdb_t::grant(mapping_t *m, space_t *new_space, vm_offset_t va)
{
m->data()->space = new_space->space();
m->data()->address = va >> PAGE_SHIFT;
} // grant()

View File

@@ -0,0 +1,24 @@
INTERFACE:
class Foo
{
};
IMPLEMENTATION [part1]:
PUBLIC
void
Foo::bar ()
{}
PROTECTED inline NEEDS [Foo::rambo]
void
Foo::baz ()
{}
IMPLEMENTATION:
PRIVATE
void
Foo::gizmatic ()
{}

View File

@@ -0,0 +1,23 @@
INTERFACE:
EXTENSION class Foo
{
int more;
};
class Bar;
IMPLEMENTATION [part2]:
#include "bar.h"
PUBLIC
void
Foo::bingo (Bar* bar)
{}
PROTECTED inline
void
Foo::rambo ()
{}

View File

@@ -0,0 +1,44 @@
INTERFACE:
class Outer
{
public:
class Inner
{
void *test() const;
template<typename R>
R *test_template() const;
};
template<typename T>
class Inner_template
{
T *test() const;
template<typename R>
R *test_template(T *a) const;
};
};
IMPLEMENTATION:
IMPLEMENT inline
void *
Outer::Inner::test() const
{ return nullptr; }
IMPLEMENT template<typename R>
R *
Outer::Inner::test_template() const
{ return nullptr; }
IMPLEMENT template<typename T>
T *
Outer::Inner_template<T>::test() const
{ return nullptr; }
IMPLEMENT template<typename T> template<typename R>
R *
Outer::Inner_template<T>::test_template(T *a) const
{ return reinterpret_cast<R *>(a); }

View File

@@ -0,0 +1,8 @@
INTERFACE:
IMPLEMENTATION:
// There is nothing to inline -- therefore, this #include directive
// should not be put in public header.
#include "foo.h"

View File

@@ -0,0 +1,88 @@
INTERFACE:
class Foo
{
};
IMPLEMENTATION:
PUBLIC
void *
Foo::operator new (size_t) // funny comment
{
}
PUBLIC
Foo&
Foo::operator + (const Foo&) // funny comment
{
}
PUBLIC
Foo&
Foo::operator = (const Foo&) // funny comment
{
}
PUBLIC
Foo&
Foo::operator * (const Foo&) // funny comment
{
}
template <typename T, typename A>
std::vector<T, A >&
operator << (std::vector<T, A>& in, const T& new_elem)
{
in.push_back (new_elem);
return in;
}
// Some systematic tests (contributed by Matthias Daum)
struct X { };
PUBLIC inline void* X::operator new(unsigned int) { return (void*)0; }
PUBLIC inline void X::operator delete(void*) { }
PUBLIC inline void* X::operator new [] (unsigned int, int) { return (void*)0; }
PUBLIC inline void X::operator delete [] (void*) { }
PUBLIC inline X X::operator + (const X&) { return *this; }
PUBLIC inline X X::operator - (const X&) { return *this; }
PUBLIC inline X X::operator * (const X&) { return *this; }
PUBLIC inline X X::operator / (const X&) { return *this; }
PUBLIC inline X X::operator % (const X&) { return *this; }
PUBLIC inline X X::operator ^ (const X&) { return *this; }
PUBLIC inline X X::operator & (const X&) { return *this; }
PUBLIC inline X X::operator | (const X&) { return *this; }
PUBLIC inline X X::operator ~ () { return *this; }
PUBLIC inline X X::operator ! () { return *this; }
PUBLIC inline X& X::operator = (const X&) {return *this; }
PUBLIC inline bool X::operator < (const X&) { return false; }
PUBLIC inline bool X::operator > (const X&) { return false; }
PUBLIC inline X& X::operator += (const X&) { return *this; }
PUBLIC inline X& X::operator -= (const X&) { return *this; }
PUBLIC inline X& X::operator *= (const X&) { return *this; }
PUBLIC inline X& X::operator /= (const X&) { return *this; }
PUBLIC inline X& X::operator %= (const X&) { return *this; }
PUBLIC inline X& X::operator ^= (const X&) { return *this; }
PUBLIC inline X& X::operator &= (const X&) { return *this; }
PUBLIC inline X& X::operator |= (const X&) { return *this; }
PUBLIC inline X X::operator << (const X&) { return *this; }
PUBLIC inline X X::operator >> (const X&) { return *this; }
PUBLIC inline X& X::operator >>= (const X&) { return *this; }
PUBLIC inline X& X::operator <<= (const X&) { return *this; }
PUBLIC inline bool X::operator == (const X&) { return true; }
PUBLIC inline bool X::operator != (const X&) { return false; }
PUBLIC inline bool X::operator <= (const X&) { return true; }
PUBLIC inline bool X::operator >= (const X&) { return true; }
PUBLIC inline bool X::operator && (const X&) { return false; }
PUBLIC inline bool X::operator || (const X&) { return true; }
PUBLIC inline X& X::operator ++ () { return *this; }
PUBLIC inline X X::operator ++ (int) { return *this; }
PUBLIC inline X& X::operator -- () { return *this; }
PUBLIC inline X X::operator -- (int) { return *this; }
PUBLIC inline X& X::operator , (const X&) { return *this; }
PUBLIC inline X* X::operator ->* (const X&) { return this; }
PUBLIC inline X* X::operator -> () { return this; }
PUBLIC inline int X::operator () (const X&) { return 0; }
PUBLIC inline int X::operator [] (const X&) { return 0; }

View File

@@ -0,0 +1,96 @@
INTERFACE:
struct Foo
{
struct Bar
{
int baz;
};
public:
int alreadythere();
inline int alsoalreadythere();
};
IMPLEMENTATION:
#include "foo.h"
inline
int bar()
{}
// Try multiline NEEDS
inline NEEDS["foo.h",
bar]
int baz()
{}
// Try NEEDS with more whitespace
inline NEEDS [ "foo.h",
bar ]
int bak()
{}
// Try function arguments
unsigned
somefunc(unsigned (*func1)(),
unsigned (*func2)())
{
}
// Try function-pointer typedef
typedef int (* diag_printf_t) (const char *, ...);
typedef int (**dblfptr) (void);
typedef int (* arrfptr[20]) (void);
// Try to initialize a nested structure object.
struct Foo::Bar some_bar = { 1 };
// And add a Foo function
void Foo::func ()
{}
// Try default arguments
void Foo::bar (int i = 15, int j = somefunc(0, somefunc(0, 0)))
{}
// Try a constructor with weird syntax
PUBLIC
Foo::Foo ()
: something (reinterpret_cast<Bar*>(Baz::bla()))
{}
// Try implementing an already-declared function
IMPLEMENT int
Foo::alreadythere()
{}
IMPLEMENT inline int
Foo::alsoalreadythere()
{}
//
// Try some commented-out code -- only #if 0 supported at the moment.
//
#if 0
#ifdef FOO
funny
#else
even funnier
#endif
#else // ! 0
void find_this ();
#if 0
but not this
#endif
#ifdef HEILIGE_WEIHNACHT
static void present_this ();
#endif
#endif

View File

@@ -0,0 +1,25 @@
INTERFACE:
IMPLEMENTATION:
extern "C" {
extern char _mappings_1, _mappings_end_1;
}
static const vm_offset_t mem_alloc_region
= reinterpret_cast<vm_offset_t>(&_mappings_1);
static const vm_offset_t mem_alloc_region_end
= reinterpret_cast<vm_offset_t>(&_mappings_end_1);
static kmem_slab_t *amm_entry_cache;
static amm_t region_amm;
static oskit_addr_t end_of_last_region;
static helping_lock_t region_lock;
static char keymap[128][2] = {
{'[', '{'},
// {']', '}'}, /* 27 */
{'+', '*'}, /* 27 */
};

View File

@@ -0,0 +1,28 @@
INTERFACE:
class T
{
};
IMPLEMENTATION:
PUBLIC
bool T::function1(void)
{
return TAG_ENABLED(tag_defined);
}
bool T::function2(void)
{
return TAG_ENABLED(tag_not_defined);
}
bool T::function3(void)
{
return TAG_ENABLED(tag_not_defined && tag_defined);
}
bool T::function4(void)
{
return TAG_ENABLED(tag_not_defined || tag_defined);
}

View File

@@ -0,0 +1,252 @@
INTERFACE:
template<class T>
class stack_t;
template<class T>
class stack_top_t
{
private:
friend class stack_t<T>;
// Dont change the layout !!, comp_and_swap2 expects
// version and _next next to each other, in that order
int _version;
T *_next;
};
template<class T>
class stack_t
{
private:
stack_top_t<T> _head;
};
IMPLEMENTATION:
//
// atomic-manipulation functions
//
// typesafe variants
template <class I>
inline bool compare_and_swap(I *ptr, I oldval, I newval)
{
return compare_and_swap(reinterpret_cast<unsigned*>(ptr),
*reinterpret_cast<unsigned*>(&oldval),
*reinterpret_cast<unsigned*>(&newval));
}
template <class I>
inline bool test_and_set(I *l)
{
return test_and_set(reinterpret_cast<unsigned*>(l));
}
//
// stack_top_t
//
// template<class T>
// stack_top_t<T> &
// stack_top_t<T>::operator=(const stack_top_t& _copy){
// _version = _copy._version;
// _next = _copy._next;
// return *this;
// }
PUBLIC inline
template<class T>
stack_top_t<T>::stack_top_t (int version, T *next)
: _version (version),
_next (next)
{}
PUBLIC inline
template<class T>
stack_top_t<T>::stack_top_t ()
: _version (0),
_next (0)
{}
//
// stack_t
//
PUBLIC
template<class T>
stack_t<T>::stack_t()
: _head (0, 0)
{}
PUBLIC
template<class T>
int
stack_t<T>::insert(T *e)
{
stack_top_t<T> old_head,
new_head;
do {
e->set_next(_head._next);
old_head = _head;
new_head._version = _head._version+1;
new_head._next = e;
} while (! compare_and_swap2((int *) &_head,
(int *) &old_head,
(int *) &new_head));
return new_head._version;
}
PUBLIC
template<class T>
T*
stack_t<T>::dequeue()
{
stack_top_t<T> old_head,
new_head;
T *first;
do {
old_head = _head;
first = _head._next;
if(! first){
break;
}
new_head._next = first->get_next();
new_head._version = _head._version + 1;
} while (! compare_and_swap2((int *) &_head,
(int *) &old_head,
(int *) &new_head));
// XXX Why did the old implementation test on e ?
// while (e && ! compare_and_swap(&_first, e, e->list_property.next));
// This is necessary to handle the case of a empty stack.
// return old_head._next;
return first;
}
// This version of dequeue only returns a value
// if it is equal to the one passed as top
PUBLIC
template<class T>
T*
stack_t<T>::dequeue(T *top)
{
stack_top_t<T> old_head,
new_head;
// stack_elem_t *first;
old_head._version = _head._version; // version doesnt matter
old_head._next = top; // cas will fail, if top aint at top
if(!_head._next){ // empty stack
return nullptr;
}
new_head._version = _head._version + 1;
new_head._next = top->get_next();
if(! compare_and_swap2((int *) &_head,
(int *) &old_head,
(int *) &new_head))
// we didnt succeed
return nullptr;
else
// top was on top , so we dequeued it
return top;
}
PUBLIC
template<class T>
T*
stack_t<T>::first()
{
return _head._next;
}
PUBLIC
template<class T>
void
stack_t<T>::reset()
{
_head._version = 0;
_head._next = 0;
}
template<class T>
stack_t<T>*
create_stack()
{
return new stack_t<T>();
}
template <>
stack_t<int>*
create_stack<int>()
{
return new stack<int>();
}
template <>
inline
stack_t<bool>*
create_stack<bool>()
{
return new stack<bool>();
}
//
// Member templates
//
class Foo
{
template <typename T> T* goo(T* t);
};
template <class Bar>
class TFoo
{
};
PUBLIC
template <typename T>
T*
Foo::bar (T* t)
{
}
IMPLEMENT
template <typename T>
T*
Foo::goo (T* t)
{
}
PUBLIC
template <class Bar>
template <typename T>
T*
TFoo::baz (T* t)
{
}
template<typename FOO,
typename = typename cxx::enable_if<!cxx::is_same<SPACE, Mem_space>::value>::type>
void
template_with_dfl_arg1()
{}
template<typename FOO,
typename = typename cxx::enable_if<!cxx::is_same<SPACE, Mem_space>::value>::type,
typename BAR>
void
template_with_dfl_arg2()
{}
template<T = int>
[[nodiscard]] T template_with_attribute()
{}

View File

@@ -0,0 +1,15 @@
INTERFACE:
template<typename T>
struct Base {};
template<typename X>
struct Derived : Base<int>
{};
IMPLEMENTATION:
PUBLIC template<typename T> inline
Derived<T>::Derived() : Base<int>()
{}

View File

@@ -0,0 +1,6 @@
IMPLEMENTATION:
int (Foo::*func_vec[100]) (int arg) =
{
0,
};

View File

@@ -0,0 +1,29 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "c-preproc.h"
#include "c-preproc_i.h"
//
// IMPLEMENTATION follows
//
#line 4 "c-preproc.cpp"
// set CS (missing from OSKIT)
#define set_cs(cs) \
asm volatile \
("ljmp %0,$1f \n1:" \
: : "i" (cs));
#line 10 "c-preproc.cpp"
void
function (void)
{
#if 1
bar ();
#else
foo ();
#endif
}

View File

@@ -0,0 +1,15 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef c_preproc_h
#define c_preproc_h
//
// INTERFACE definition follows
//
#line 11 "c-preproc.cpp"
void
function (void);
#endif // c_preproc_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef c_preproc_i_h
#define c_preproc_i_h
#include "c-preproc.h"
#endif // c_preproc_i_h

View File

@@ -0,0 +1,35 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "comment_in_string.h"
#include "comment_in_string_i.h"
//
// IMPLEMENTATION follows
//
#line 4 "comment_in_string.cpp"
int foo(char *s);
#line 6 "comment_in_string.cpp"
void irq_init(unsigned char master_base, unsigned char slave_base)
{
if (!(foo(" -vmware"))
{
foo("outb_p(MASTER_OCW, 0xfb); // unmask irq2");
}
else
{
foo("using normal pic mode \n");
}
}
#line 18 "comment_in_string.cpp"
void bar()
{
foo ("if (0) {");
foo ("} // if(0)");
}

View File

@@ -0,0 +1,17 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef comment_in_string_h
#define comment_in_string_h
//
// INTERFACE definition follows
//
#line 7 "comment_in_string.cpp"
void irq_init(unsigned char master_base, unsigned char slave_base);
#line 19 "comment_in_string.cpp"
void bar();
#endif // comment_in_string_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef comment_in_string_i_h
#define comment_in_string_i_h
#include "comment_in_string.h"
#endif // comment_in_string_i_h

View File

@@ -0,0 +1,18 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "default_args.h"
#include "default_args_i.h"
//
// IMPLEMENTATION follows
//
#line 26 "default_args.cpp"
extern "C"
void
disasm_bytes(char *buffer, unsigned len, unsigned va, unsigned task,
int show_symbols, int show_intel_syntax,
int (*peek_task)(unsigned addr, unsigned task),
const char* (*get_symbol)(unsigned addr, unsigned task)) WEAK;

View File

@@ -0,0 +1,52 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef default_args_h
#define default_args_h
//
// INTERFACE definition follows
//
#line 6 "default_args.cpp"
template <typename T> std::vector<T>
vec(T f1 = T(), T f2 = T(), T f3 = T(),
T f4 = T(), T f5 = T(), T f6 = T());
//
// IMPLEMENTATION includes follow (for use by inline functions/templates)
//
#line 1 "default_args.cpp"
#include <vector>
//
// IMPLEMENTATION of function templates
//
#line 4 "default_args.cpp"
template <typename T> std::vector<T>
vec(T f1, T f2, T f3,
T f4, T f5, T f6)
{
std::vector<T> v;
if (f1 != T()) {
v.push_back (f1);
if (f2 != T()) {
v.push_back (f2);
if (f3 != T()) {
v.push_back (f3);
if (f4 != T()) {
v.push_back (f4);
if (f5 != T()) {
v.push_back (f5);
if (f6 != T()) {
v.push_back (f6);
}}}}}}
return v;
}
#endif // default_args_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef default_args_i_h
#define default_args_i_h
#include "default_args.h"
#endif // default_args_i_h

View File

@@ -0,0 +1,5 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_multi1.h"
#include "drop_multi1_i.h"

View File

@@ -0,0 +1,44 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_multi1.h"
#include "drop_multi1_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection.cpp"
void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
#line 26 "dropsection.cpp"
void
Gen_foo_ext::test()
{
// the test
}
#line 44 "dropsection.cpp"
int
Gen_foo::foo( int y )
{
// just return y
return y;
}
#line 53 "dropsection.cpp"
int
Gen_foo::tust( int y )
{
// just return y
return y;
}

View File

@@ -0,0 +1,43 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_multi1_h
#define drop_multi1_h
//
// INTERFACE definition follows
//
#line 2 "dropsection.cpp"
class Gen_foo
{
public:
int baz;
protected:
int foo( int );
public:
#line 21 "dropsection.cpp"
void
bar( unsigned x );
#line 54 "dropsection.cpp"
int
tust( int y );
};
#line 12 "dropsection.cpp"
class Gen_foo_ext : private Gen_foo, public Ixdebix
{
protected:
unsigned stuff;
public:
#line 27 "dropsection.cpp"
void
test();
};
#endif // drop_multi1_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_multi1_i_h
#define drop_multi1_i_h
#include "drop_multi1.h"
#endif // drop_multi1_i_h

View File

@@ -0,0 +1,18 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_multi2.h"
#include "drop_multi2_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection-ext.cpp"
int
Gen_foo::do_something_private()
{
// just do it
}

View File

@@ -0,0 +1,44 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_multi2.h"
#include "drop_multi2_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection.cpp"
void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
#line 26 "dropsection.cpp"
void
Gen_foo_ext::test()
{
// the test
}
#line 44 "dropsection.cpp"
int
Gen_foo::foo( int y )
{
// just return y
return y;
}
#line 53 "dropsection.cpp"
int
Gen_foo::tust( int y )
{
// just return y
return y;
}

View File

@@ -0,0 +1,72 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_multi2_h
#define drop_multi2_h
//
// INTERFACE definition follows
//
#line 2 "dropsection.cpp"
class Gen_foo
#line 7 "dropsection-ext.cpp"
: public Gen_bar
#line 4 "dropsection.cpp"
{
public:
int baz;
protected:
int foo( int );
private: // EXTENSION
#line 8 "dropsection-ext.cpp"
public:
int extra_var;
public:
#line 21 "dropsection.cpp"
void
bar( unsigned x );
#line 54 "dropsection.cpp"
int
tust( int y );
private:
#line 21 "dropsection-ext.cpp"
int
do_something_private();
};
#line 12 "dropsection.cpp"
class Gen_foo_ext : private Gen_foo, public Ixdebix
#line 13 "dropsection-ext.cpp"
, public Gen_baz
#line 14 "dropsection.cpp"
{
protected:
unsigned stuff;
private: // EXTENSION
#line 14 "dropsection-ext.cpp"
private:
char *extension;
public:
#line 27 "dropsection.cpp"
void
test();
};
#endif // drop_multi2_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_multi2_i_h
#define drop_multi2_i_h
#include "drop_multi2.h"
#endif // drop_multi2_i_h

View File

@@ -0,0 +1,35 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_single1.h"
#include "drop_single1_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection.cpp"
void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
#line 26 "dropsection.cpp"
void
Gen_foo_ext::test()
{
// the test
}
#line 53 "dropsection.cpp"
int
Gen_foo::tust( int y )
{
// just return y
return y;
}

View File

@@ -0,0 +1,43 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single1_h
#define drop_single1_h
//
// INTERFACE definition follows
//
#line 2 "dropsection.cpp"
class Gen_foo
{
public:
int baz;
protected:
int foo( int );
public:
#line 21 "dropsection.cpp"
void
bar( unsigned x );
#line 54 "dropsection.cpp"
int
tust( int y );
};
#line 12 "dropsection.cpp"
class Gen_foo_ext : private Gen_foo, public Ixdebix
{
protected:
unsigned stuff;
public:
#line 27 "dropsection.cpp"
void
test();
};
#endif // drop_single1_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single1_i_h
#define drop_single1_i_h
#include "drop_single1.h"
#endif // drop_single1_i_h

View File

@@ -0,0 +1,36 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_single2.h"
#include "drop_single2_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection.cpp"
void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
#line 26 "dropsection.cpp"
void
Gen_foo_ext::test()
{
// the test
}
#line 34 "dropsection.cpp"
int
Gen_foo::foo( int y )
{
// do something strange with y
bar(y);
return y;
}

View File

@@ -0,0 +1,39 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single2_h
#define drop_single2_h
//
// INTERFACE definition follows
//
#line 2 "dropsection.cpp"
class Gen_foo
{
public:
int baz;
protected:
int foo( int );
public:
#line 21 "dropsection.cpp"
void
bar( unsigned x );
};
#line 12 "dropsection.cpp"
class Gen_foo_ext : private Gen_foo, public Ixdebix
{
protected:
unsigned stuff;
public:
#line 27 "dropsection.cpp"
void
test();
};
#endif // drop_single2_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single2_i_h
#define drop_single2_i_h
#include "drop_single2.h"
#endif // drop_single2_i_h

View File

@@ -0,0 +1,44 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "drop_single3.h"
#include "drop_single3_i.h"
//
// IMPLEMENTATION follows
//
#line 20 "dropsection.cpp"
void
Gen_foo::bar( unsigned x )
{
// do soemthing with x;
}
#line 26 "dropsection.cpp"
void
Gen_foo_ext::test()
{
// the test
}
#line 44 "dropsection.cpp"
int
Gen_foo::foo( int y )
{
// just return y
return y;
}
#line 53 "dropsection.cpp"
int
Gen_foo::tust( int y )
{
// just return y
return y;
}

View File

@@ -0,0 +1,43 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single3_h
#define drop_single3_h
//
// INTERFACE definition follows
//
#line 2 "dropsection.cpp"
class Gen_foo
{
public:
int baz;
protected:
int foo( int );
public:
#line 21 "dropsection.cpp"
void
bar( unsigned x );
#line 54 "dropsection.cpp"
int
tust( int y );
};
#line 12 "dropsection.cpp"
class Gen_foo_ext : private Gen_foo, public Ixdebix
{
protected:
unsigned stuff;
public:
#line 27 "dropsection.cpp"
void
test();
};
#endif // drop_single3_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef drop_single3_i_h
#define drop_single3_i_h
#include "drop_single3.h"
#endif // drop_single3_i_h

View File

@@ -0,0 +1,16 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "explicit.h"
#include "explicit_i.h"
//
// IMPLEMENTATION follows
//
#line 8 "explicit.cpp"
Foo::Foo (int bar)
{}

View File

@@ -0,0 +1,20 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef explicit_h
#define explicit_h
//
// INTERFACE definition follows
//
#line 2 "explicit.cpp"
class Foo
{
public:
#line 10 "explicit.cpp"
explicit Foo (int bar);
};
#endif // explicit_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef explicit_i_h
#define explicit_i_h
#include "explicit.h"
#endif // explicit_i_h

View File

@@ -0,0 +1,5 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "extension_inherit.h"
#include "extension_inherit_i.h"

View File

@@ -0,0 +1,285 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef extension_inherit_h
#define extension_inherit_h
//
// INTERFACE definition follows
//
#line 2 "extension_inherit.cpp"
// Variable number of class inheritance extensions
class Class_b0_e1
#line 9 "extension_inherit.cpp"
: Ext_base_0
#line 6 "extension_inherit.cpp"
{
private: // EXTENSION
#line 10 "extension_inherit.cpp"
};
#line 12 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b0_e1_e1
#line 18 "extension_inherit.cpp"
: Ext_base_0
#line 22 "extension_inherit.cpp"
, Ext2_base_0
#line 15 "extension_inherit.cpp"
{
private: // EXTENSION
#line 19 "extension_inherit.cpp"
private: // EXTENSION
#line 23 "extension_inherit.cpp"
};
#line 25 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b0_e2
#line 31 "extension_inherit.cpp"
: Ext_base_0, Ext_base_1
#line 28 "extension_inherit.cpp"
{
private: // EXTENSION
#line 32 "extension_inherit.cpp"
};
#line 34 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b0_e2_e1
#line 40 "extension_inherit.cpp"
: Ext_base_0, Ext_base_1
#line 44 "extension_inherit.cpp"
, Ext2_base_0
#line 37 "extension_inherit.cpp"
{
private: // EXTENSION
#line 41 "extension_inherit.cpp"
private: // EXTENSION
#line 45 "extension_inherit.cpp"
};
#line 47 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b1_e1 : Base_0
#line 53 "extension_inherit.cpp"
, Ext_base_0
#line 50 "extension_inherit.cpp"
{
private: // EXTENSION
#line 54 "extension_inherit.cpp"
};
#line 56 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b1_e1_e1 : Base_0
#line 62 "extension_inherit.cpp"
, Ext_base_0
#line 66 "extension_inherit.cpp"
, Ext2_base_0
#line 59 "extension_inherit.cpp"
{
private: // EXTENSION
#line 63 "extension_inherit.cpp"
private: // EXTENSION
#line 67 "extension_inherit.cpp"
};
#line 69 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b1_e2 : Base_0
#line 75 "extension_inherit.cpp"
, Ext_base_0, Ext_base_1
#line 72 "extension_inherit.cpp"
{
private: // EXTENSION
#line 76 "extension_inherit.cpp"
};
#line 78 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b1_e2_e1 : Base_0
#line 84 "extension_inherit.cpp"
, Ext_base_0, Ext_base_1
#line 88 "extension_inherit.cpp"
, Ext2_base_0
#line 81 "extension_inherit.cpp"
{
private: // EXTENSION
#line 85 "extension_inherit.cpp"
private: // EXTENSION
#line 89 "extension_inherit.cpp"
};
#line 91 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b2_e1 : Base_0, Base_1
#line 97 "extension_inherit.cpp"
, Ext_base_0
#line 94 "extension_inherit.cpp"
{
private: // EXTENSION
#line 98 "extension_inherit.cpp"
};
#line 100 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b2_e1_e1 : Base_0, Base_1
#line 106 "extension_inherit.cpp"
, Ext_base_0
#line 110 "extension_inherit.cpp"
, Ext2_base_0
#line 103 "extension_inherit.cpp"
{
private: // EXTENSION
#line 107 "extension_inherit.cpp"
private: // EXTENSION
#line 111 "extension_inherit.cpp"
};
#line 113 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b2_e2 : Base_0, Base_1
#line 119 "extension_inherit.cpp"
, Ext_base_0, Ext_base_1
#line 116 "extension_inherit.cpp"
{
private: // EXTENSION
#line 120 "extension_inherit.cpp"
};
#line 122 "extension_inherit.cpp"
// ----------------------------------------------------------------------
class Class_b2_e2_e1 : Base_0, Base_1
#line 128 "extension_inherit.cpp"
, Ext_base_0, Ext_base_1
#line 132 "extension_inherit.cpp"
, Ext2_base_0
#line 125 "extension_inherit.cpp"
{
private: // EXTENSION
#line 129 "extension_inherit.cpp"
private: // EXTENSION
#line 133 "extension_inherit.cpp"
};
#line 135 "extension_inherit.cpp"
// Variable spacing around class inheritance extensions
class Class_var : Base_0 /* Unconvenient comment
that wraps around */
#line 145 "extension_inherit.cpp"
, Ext_base_0
#line 149 "extension_inherit.cpp"
, Ext2_base_0
#line 153 "extension_inherit.cpp"
, Ext3_base_0
#line 141 "extension_inherit.cpp"
{
private: // EXTENSION
#line 146 "extension_inherit.cpp"
private: // EXTENSION
#line 150 "extension_inherit.cpp"
private: // EXTENSION
#line 153 "extension_inherit.cpp"
};
#endif // extension_inherit_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef extension_inherit_i_h
#define extension_inherit_i_h
#include "extension_inherit.h"
#endif // extension_inherit_i_h

View File

@@ -0,0 +1,16 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "extern_c.h"
#include "extern_c_i.h"
//
// IMPLEMENTATION follows
//
#line 4 "extern_c.cpp"
extern "C"
{
extern char _mappings_1, _mappings_end_1;
}

View File

@@ -0,0 +1,6 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef extern_c_h
#define extern_c_h
#endif // extern_c_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef extern_c_i_h
#define extern_c_i_h
#include "extern_c.h"
#endif // extern_c_i_h

View File

@@ -0,0 +1,77 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "func_defs.h"
#include "func_defs_i.h"
//
// IMPLEMENTATION follows
//
#line 8 "func_defs.cpp"
void
Test::func1() const throw()
{}
#line 13 "func_defs.cpp"
void
Test::func2() throw(int, char const *)
{};
#line 18 "func_defs.cpp"
void
Test::func3(unsigned) noexcept
{}
#line 23 "func_defs.cpp"
void
Test::func4(int) noexcept ( this->func2() )
{}
#line 28 "func_defs.cpp"
Test::Test(int) noexcept(true) __attribute__ (( test("str") ))
: init(This)
{}
#line 33 "func_defs.cpp"
void
Test::func5() noexcept ( this->func2() ) [[test(attr)]] [[test2]]
{}
#line 38 "func_defs.cpp"
[[cppattr]] [[another_attr]] int
Test::func_attr_no_needs()
{}
#line 43 "func_defs.cpp"
[[anattr]] int
Test::func_attr_needs()
{}
#line 52 "func_defs.cpp"
/**
* This is the comment for `free_function`.
*/
Test const &
free_function(int, long a) noexcept
{
return Test(a);
}

View File

@@ -0,0 +1,59 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef func_defs_h
#define func_defs_h
//
// INTERFACE definition follows
//
#line 2 "func_defs.cpp"
class Test
{
public:
#line 10 "func_defs.cpp"
void
func1() const throw();
#line 15 "func_defs.cpp"
void
func2() throw(int, char const *) override final;
#line 20 "func_defs.cpp"
void
func3(unsigned) noexcept final override;
#line 25 "func_defs.cpp"
void
func4(int) noexcept ( this->func2() );
#line 30 "func_defs.cpp"
explicit Test(int) noexcept(true) __attribute__ (( test("str") )) final;
#line 35 "func_defs.cpp"
void
func5() noexcept ( this->func2() ) [[test(attr)]] [[test2]];
#line 40 "func_defs.cpp"
[[cppattr]] [[another_attr]] static int
func_attr_no_needs();
#line 45 "func_defs.cpp"
[[anattr]] int
func_attr_needs();
#line 50 "func_defs.cpp"
int attribute((foo("murx("))) [[this->is->a->test]]
func_with_stupid_attributes(Tmpl<Type> x) const && throw() = default;
};
#line 53 "func_defs.cpp"
/**
* This is the comment for `free_function`.
*/
Test const &
free_function(int, long a) noexcept;
#endif // func_defs_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef func_defs_i_h
#define func_defs_i_h
#include "func_defs.h"
#endif // func_defs_i_h

View File

@@ -0,0 +1,28 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "implement_default.h"
#include "implement_default_i.h"
//
// IMPLEMENTATION follows
//
#line 19 "implement_default.cpp"
void Test::warn_func1() { /* this is the override */ }
#line 20 "implement_default.cpp"
void Test::warn_func2() { /* this is the override */ }
#line 25 "implement_default.cpp"
void Test::func1() { /* this is the override */ }
#line 26 "implement_default.cpp"
void Test::func2() { /* this is the override */ }
#line 29 "implement_default.cpp"
void Test::defl() { /* this is the default */ }

View File

@@ -0,0 +1,25 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef implement_default_h
#define implement_default_h
//
// INTERFACE definition follows
//
#line 2 "implement_default.cpp"
class Test
{
public:
void warn_func1();
void warn_func2();
void func1();
void func2();
void defl();
// skip this as the test cannot deal with errors
// void err_func1();
};
#endif // implement_default_h

View File

@@ -0,0 +1,3 @@
implement_default.cpp:19: warning: Function Test::warn_func1 overrides an IMPLEMENT_DEFAULT function but does not use IMPLEMENT_OVERRIDE
implement_default.cpp:20: warning: Function Test::warn_func2 overrides an IMPLEMENT_DEFAULT function but does not use IMPLEMENT_OVERRIDE
warning: found 2 warning(s)

View File

@@ -0,0 +1 @@
implement_default_err.cpp:10: error: No default implementation for Test::err_func1 found

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef implement_default_i_h
#define implement_default_i_h
#include "implement_default.h"
#endif // implement_default_i_h

View File

@@ -0,0 +1,5 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "implement_template.h"
#include "implement_template_i.h"

View File

@@ -0,0 +1,58 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef implement_template_h
#define implement_template_h
//
// INTERFACE definition follows
//
#line 2 "implement_template.cpp"
template< typename T >
class Test
{
public:
void test_func();
public:
#line 23 "implement_template.cpp"
// comment 2
// comment 1
template<
typename X, // comment within template args list
typename X2 // another comment in tl args
> void __attribute__((deprecated))
test_func2();
};
//
// IMPLEMENTATION of function templates
//
#line 12 "implement_template.cpp"
// comment
template< typename T > void __attribute__((deprecated))
Test<T>::test_func()
{
}
#line 20 "implement_template.cpp"
// comment 2
// comment 1
template< typename T > template<
typename X, // comment within template args list
typename X2 // another comment in tl args
> void __attribute__((deprecated))
Test<T>::test_func2<X, X2>()
{
}
#endif // implement_template_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef implement_template_i_h
#define implement_template_i_h
#include "implement_template.h"
#endif // implement_template_i_h

View File

@@ -0,0 +1,47 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "inline.h"
#include "inline_i.h"
//
// IMPLEMENTATION follows
//
#line 60 "inline.cpp"
// This inline funtion is public only because it is needed by an
// extern-"C" function. So we do not want to export it.
inline void
Foo::bar()
{
}
#line 69 "inline.cpp"
// Try both NOEXPORT and NEEDED.
inline void
Foo::baz()
{
}
#line 83 "inline.cpp"
constexpr void
Foo::cexpr2()
{
}
#line 101 "inline.cpp"
extern "C"
void function (Foo* f)
{
f->bar();
f->cexpr2();
}

View File

@@ -0,0 +1,168 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef inline_h
#define inline_h
//
// INTERFACE definition follows
//
#line 2 "inline.cpp"
class Foo
{
public:
#line 61 "inline.cpp"
// This inline funtion is public only because it is needed by an
// extern-"C" function. So we do not want to export it.
inline void
bar();
#line 70 "inline.cpp"
// Try both NOEXPORT and NEEDED.
inline void
baz();
#line 78 "inline.cpp"
constexpr void
cexpr1();
#line 85 "inline.cpp"
constexpr void
cexpr2();
private:
#line 32 "inline.cpp"
inline bool
private_func();
};
#line 6 "inline.cpp"
class Bar
{
public:
#line 56 "inline.cpp"
inline void
public_func();
private:
#line 38 "inline.cpp"
inline bool
private_func();
#line 50 "inline.cpp"
inline void
another_private_func();
};
#line 10 "inline.cpp"
class Cexpr
{
constexpr test1();
};
#line 102 "inline.cpp"
extern "C"
void function (Foo* f);
#line 109 "inline.cpp"
template <typename T> inline void* xcast(T* t);
//
// IMPLEMENTATION of inline functions (and needed classes)
//
#line 18 "inline.cpp"
// Test dependency-chain resolver
class Frob
{
private:
#line 26 "inline.cpp"
inline bool
private_func();
#line 44 "inline.cpp"
constexpr bool
private_cexpr();
};
#line 30 "inline.cpp"
inline bool
Foo::private_func()
{
}
#line 76 "inline.cpp"
constexpr void
Foo::cexpr1()
{
}
#line 36 "inline.cpp"
inline bool
Bar::private_func()
{
}
#line 48 "inline.cpp"
inline void
Bar::another_private_func()
{
}
#line 24 "inline.cpp"
inline bool
Frob::private_func()
{
}
#line 54 "inline.cpp"
inline void
Bar::public_func()
{
}
#line 89 "inline.cpp"
constexpr void
Cexpr::test1()
{
}
#line 95 "inline.cpp"
constexpr void
Cexpr::test2()
{
}
#line 108 "inline.cpp"
template <typename T> inline void* xcast(T* t)
{
return (void*) t;
}
#endif // inline_h

View File

@@ -0,0 +1,20 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef inline_i_h
#define inline_i_h
#include "inline.h"
//
// IMPLEMENTATION of inline functions follows
//
#line 42 "inline.cpp"
constexpr bool
Frob::private_cexpr()
{
}
#endif // inline_i_h

View File

@@ -0,0 +1,87 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "inline_noinline.h"
#include "inline_noinline_i.h"
//
// IMPLEMENTATION follows
//
#line 83 "inline.cpp"
constexpr void
Foo::cexpr2()
{
}
#line 24 "inline.cpp"
bool
Frob::private_func()
{
}
#line 30 "inline.cpp"
bool
Foo::private_func()
{
}
#line 36 "inline.cpp"
bool
Bar::private_func()
{
}
#line 48 "inline.cpp"
void
Bar::another_private_func()
{
}
#line 54 "inline.cpp"
void
Bar::public_func()
{
}
#line 60 "inline.cpp"
// This inline funtion is public only because it is needed by an
// extern-"C" function. So we do not want to export it.
void
Foo::bar()
{
}
#line 69 "inline.cpp"
// Try both NOEXPORT and NEEDED.
void
Foo::baz()
{
}
#line 101 "inline.cpp"
extern "C"
void function (Foo* f)
{
f->bar();
f->cexpr2();
}

View File

@@ -0,0 +1,117 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef inline_noinline_h
#define inline_noinline_h
//
// INTERFACE definition follows
//
#line 2 "inline.cpp"
class Foo
{
public:
#line 61 "inline.cpp"
// This inline funtion is public only because it is needed by an
// extern-"C" function. So we do not want to export it.
void
bar();
#line 70 "inline.cpp"
// Try both NOEXPORT and NEEDED.
void
baz();
#line 78 "inline.cpp"
constexpr void
cexpr1();
#line 85 "inline.cpp"
constexpr void
cexpr2();
private:
#line 32 "inline.cpp"
bool
private_func();
};
#line 6 "inline.cpp"
class Bar
{
public:
#line 56 "inline.cpp"
void
public_func();
private:
#line 38 "inline.cpp"
bool
private_func();
#line 50 "inline.cpp"
void
another_private_func();
};
#line 10 "inline.cpp"
class Cexpr
{
constexpr test1();
};
#line 102 "inline.cpp"
extern "C"
void function (Foo* f);
#line 109 "inline.cpp"
template <typename T> void* xcast(T* t);
//
// IMPLEMENTATION of inline functions (and needed classes)
//
#line 76 "inline.cpp"
constexpr void
Foo::cexpr1()
{
}
#line 89 "inline.cpp"
constexpr void
Cexpr::test1()
{
}
#line 95 "inline.cpp"
constexpr void
Cexpr::test2()
{
}
//
// IMPLEMENTATION of function templates
//
#line 108 "inline.cpp"
template <typename T> void* xcast(T* t)
{
return (void*) t;
}
#endif // inline_noinline_h

View File

@@ -0,0 +1,41 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef inline_noinline_i_h
#define inline_noinline_i_h
#include "inline_noinline.h"
//
// INTERFACE internal declaration follows
//
#line 18 "inline.cpp"
// Test dependency-chain resolver
class Frob
{
private:
#line 26 "inline.cpp"
bool
private_func();
#line 44 "inline.cpp"
constexpr bool
private_cexpr();
};
//
// IMPLEMENTATION of inline functions follows
//
#line 42 "inline.cpp"
constexpr bool
Frob::private_cexpr()
{
}
#endif // inline_noinline_i_h

View File

@@ -0,0 +1,19 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "interfacepublic.h"
#include "interface_i.h"
//
// IMPLEMENTATION follows
//
#line 9 "interface.cpp"
void
Foo::func1()
{
}

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef interface_i_h
#define interface_i_h
#include "interfacepublic.h"
#endif // interface_i_h

View File

@@ -0,0 +1,22 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef interface_h
#define interface_h
//
// INTERFACE definition follows
//
#line 2 "interface.cpp"
// This is class Foo.
class Foo
{
public:
#line 11 "interface.cpp"
void
func1();
};
#endif // interface_h

View File

@@ -0,0 +1,24 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "line.h"
#include "line_i.h"
//
// IMPLEMENTATION follows
//
#line 9 "line.cpp"
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
void
Foo::func1()
{
}

View File

@@ -0,0 +1,28 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_h
#define line_h
//
// INTERFACE definition follows
//
#line 2 "line.cpp"
// This is class Foo.
class Foo
{
public:
#line 10 "line.cpp"
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
static void
func1();
};
#endif // line_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_i_h
#define line_i_h
#include "line.h"
#endif // line_i_h

View File

@@ -0,0 +1,24 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "line_nh.h"
#include "line_nh_i.h"
//
// IMPLEMENTATION follows
//
#line 9 "line.cpp"
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
void
Foo::func1()
{
}

View File

@@ -0,0 +1,22 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_nh_h
#define line_nh_h
//
// INTERFACE definition follows
//
// This is class Foo.
class Foo
{
public:
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
static void func1();
};
#endif // line_nh_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_nh_i_h
#define line_nh_i_h
#include "line_nh.h"
#endif // line_nh_i_h

View File

@@ -0,0 +1,21 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "line_not.h"
#include "line_not_i.h"
//
// IMPLEMENTATION follows
//
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
void
Foo::func1()
{
}

View File

@@ -0,0 +1,22 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_not_h
#define line_not_h
//
// INTERFACE definition follows
//
// This is class Foo.
class Foo
{
public:
// A long, multiline comment in front of this function definition.
// Also, a lot of specifiers that need to be handled.
static void func1();
};
#endif // line_not_h

View File

@@ -0,0 +1,7 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef line_not_i_h
#define line_not_i_h
#include "line_not.h"
#endif // line_not_i_h

View File

@@ -0,0 +1,735 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "mapping.h"
#include "mapping_i.h"
//
// IMPLEMENTATION follows
//
#line 48 "mapping.cpp"
// The mapping database.
// This implementation encodes mapping trees in very compact arrays of
// fixed sizes, prefixed by a tree header (mapping_tree_t). Array
// sizes can vary from 4 mappings to 4<<15 mappings. For each size,
// we set up a slab allocator. To grow or shrink the size of an
// array, we have to allocate a larger or smaller tree from the
// corresponding allocator and then copy the array elements.
//
// The array elements (mapping_t) contain a tree depth element. This
// depth and the relative position in the array is all information we
// need to derive tree structure information. Here is an example:
//
// array
// element depth
// number value comment
// --------------------------
// 0 0 Sigma0 mapping
// 1 1 child of element #0 with depth 0
// 2 2 child of element #1 with depth 1
// 3 2 child of element #1 with depth 1
// 4 3 child of element #3 with depth 2
// 5 2 child of element #1 with depth 1
// 6 3 child of element #5 with depth 2
// 7 1 child of element #0 with depth 0
//
// This array is a pre-order encoding of the following tree:
//
// 0
// / \
// 1 7
// / | \
// 2 3 5
// | |
// 4 6
// IDEAS for enhancing this implementation:
// We often have to find a tree header corresponding to a mapping.
// Currently, we do this by iterating backwards over the array
// containing the mappings until we find the Sigma0 mapping, from
// whose address we can compute the address of the tree header. If
// this becomes a problem, we could add one more byte to the mappings
// with a hint (negative array offset) where to find the sigma0
// mapping. (If the hint value overflows, just iterate using the hint
// value of the mapping we find with the first hint value.) Another
// idea (from Adam) would be to just look up the tree header by using
// the physical address from the page-table lookup, but we would need
// to change the interface of the mapping database for that (pass in
// the physical address at all times), or we would have to include the
// physical address (or just the address of the tree header) in the
// mapdb_t-user-visible mapping_t (which could be different from the
// internal tree representation). (XXX: Implementing one of these
// ideas is probably worthwile doing!)
// Instead of copying whole trees around when they grow or shrink a
// lot, or copying parts of trees when inserting an element, we could
// give up the array representation and add a "next" pointer to the
// elements -- that is, keep the tree of mappings in a
// pre-order-encoded singly-linked list (credits to: Christan Szmajda
// and Adam Wiggins). 24 bits would probably be enough to encode that
// pointer. Disadvantages: Mapping entries would be larger, and the
// cache-friendly space-locality of tree entries would be lost.
// The current handling of superpages sucks rocks both in this module
// and in our user, ipc_map.cc. We could support multiple page sizes
// by not using a physframe[] array only for the largest page size.
// (Entries of that array point to the top-level mappings -- sigma0
// mappings.) Mapping-tree entries would then either be regular
// mappings or pointers to an array of mappings of the next-smaller
// size. (credits: Christan Szmajda)
//
// physframe[]
// -------------------------------
// | | | | | | | | | | | | | | | | array of ptr to 4M mapping_tree_t's
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t *or* ptr to array of ptr to 4K trees
// | | e.g.
// | ----------------|
// | | v array of ptr to 4M mapping_tree_t's
// --------------- -------------------------------
// | | | | | | | | | | | | | | | |
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t
// | |
// | |
// | |
// ---------------
//-
#line 151 "mapping.cpp"
#ifndef offsetof // should be defined in stddef.h, but isn't
#line 153 "mapping.cpp"
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#line 154 "mapping.cpp"
#endif
#line 176 "mapping.cpp"
// public routines with inline implementations
unsigned
mapping_tree_t::number_of_entries() const
{
return mapdb_t::Size_factor << _size_id;
}
#line 184 "mapping.cpp"
mapping_t *
mapping_tree_t::mappings()
{
return & _mappings[0];
}
#line 211 "mapping.cpp"
mapping_t::mapping_t()
{}
#line 215 "mapping.cpp"
mapping_s *
mapping_t::data()
{
return reinterpret_cast<mapping_s*>(_data);
}
#line 222 "mapping.cpp"
space_index_t
mapping_t::space()
{
return space_index_t(data()->space);
}
#line 229 "mapping.cpp"
vm_offset_t
mapping_t::vaddr()
{
return (data()->address << PAGE_SHIFT);
}
#line 236 "mapping.cpp"
vm_size_t
mapping_t::size()
{
if ( data()->size )
return SUPERPAGE_SIZE;
else
return PAGE_SIZE;
}
#line 246 "mapping.cpp"
mapping_type_t
mapping_t::type()
{
// return data()->type;;
return Map_mem;
}
#line 254 "mapping.cpp"
bool
mapping_t::unused()
{
return (data()->depth > Depth_max);
}
#line 261 "mapping.cpp"
mapping_tree_t *
mapping_t::tree()
{
mapping_t *m = this;
while (m->data()->depth > Depth_sigma0_mapping)
{
// jump in bigger steps if this is not a free mapping
if (! m->unused())
{
m -= m->data()->depth;
continue;
}
m--;
}
return reinterpret_cast<mapping_tree_t *>
(reinterpret_cast<char *>(m) - offsetof(mapping_tree_t, _mappings));
}
#line 282 "mapping.cpp"
//
// more of class mapping_t
//
mapping_t *
mapping_t::parent()
{
if (data()->depth <= Depth_sigma0_mapping)
{
// Sigma0 mappings don't have a parent.
return nullptr;
}
// Iterate over mapping entries of this tree backwards until we find
// an entry with a depth smaller than ours. (We assume here that
// "special" depths (empty, end) are larger than Depth_max.)
mapping_t *m = this - 1;
while (m->data()->depth >= data()->depth)
m--;
return m;
}
#line 306 "mapping.cpp"
mapping_t *
mapping_t::next_iter()
{
mapping_tree_t *t = tree();
mapping_t *last_in_tree = t->mappings() + t->number_of_entries() - 1;
mapping_t *m = this;
// Look for a valid element in the tree structure.
while (m != last_in_tree)
{
m++;
if (! m->unused())
return m; // Found a valid entry!
// Don't iterate to end of tree if this is the last tree entry.
if (m->data()->depth == Depth_end)
return 0;
}
// Couldn't find a non-empty element behind ourselves in the tree
// structure.
return 0;
}
#line 331 "mapping.cpp"
mapping_t *
mapping_t::next_child(mapping_t *parent)
{
// Find the next valid entry in the tree structure.
mapping_t *m = next_iter();
// If we didn't find an entry, or if the entry cannot be a child of
// "parent", return nullptr
if (m == 0
|| m->data()->depth <= parent->data()->depth)
return nullptr;
return m; // Found!
}
#line 346 "mapping.cpp"
// helpers
//
// class mapping_tree_t
//
// This function copies the elements of mapping tree src to mapping
// tree dst, ignoring empty elements (that is, compressing the
// source tree. In-place compression is supported.
void
mapping_tree_t::copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src)
{
dst->_count = 0;
dst->_empty_count = 0;
mapping_t *d = dst->mappings();
for (mapping_t *s = src->mappings();
s < src->mappings() + src->number_of_entries();
s++)
{
if (s->unused()) // entry free
{
if (s->data()->depth == Depth_end)
break;
continue;
}
*d++ = *s;
dst->_count += 1;
}
assert (dst->_count == src->_count);
assert (d < dst->mappings() + dst->number_of_entries());
d->data()->depth = Depth_end;
dst->mappings()[dst->number_of_entries() - 1].data()->depth = Depth_end;
} // copy_compact_tree()
#line 397 "mapping.cpp"
mapdb_t::mapdb_t()
{
vm_offset_t page_number = kmem::info()->main_memory.high / PAGE_SIZE + 1;
// allocate physframe array
check ( physframe = reinterpret_cast<physframe_data *>
(kmem::alloc(page_number * sizeof(physframe_data))) );
memset(physframe, 0, page_number * sizeof(physframe_data));
// create a slab for each mapping tree size
for (int slab_number = 0;
slab_number <= Size_id_max;
slab_number++ )
{
unsigned elem_size =
(Size_factor << slab_number) * sizeof(mapping_t)
+ sizeof(mapping_tree_t);
allocator_for_treesize[slab_number] =
new kmem_slab_t(((PAGE_SIZE / elem_size) < 40
? 8*PAGE_SIZE : PAGE_SIZE),
elem_size, 1);
}
// create a sigma0 mapping for all physical pages
for (unsigned page_id = 0; page_id < page_number; page_id++)
{
mapping_tree_t *t;
check( (t = physframe[page_id].tree
= reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[0]->alloc())) );
t->_count = 1; // 1 valid mapping
t->_size_id = 0; // size is equal to Size_factor << 0
t->_empty_count = 0; // no gaps in tree representation
t->mappings()[0].data()->depth = Depth_sigma0_mapping;
t->mappings()[0].data()->address = page_id;
t->mappings()[0].data()->space = config::sigma0_taskno;
t->mappings()[0].data()->size = 0;
t->mappings()[1].data()->depth = Depth_end;
// We also always set the end tag on last entry so that we can
// check whether it has been overwritten.
t->mappings()[t->number_of_entries() - 1].data()->depth = Depth_end;
}
} // mapdb_t()
#line 448 "mapping.cpp"
// insert a new mapping entry with the given values as child of
// "parent" After locating the right place for the new entry, it will
// be stored there (if this place is empty) or the following entries
// moved by one entry.
// We assume that there is at least one free entry at the end of the
// array so that at least one insert() operation can succeed between a
// lock()/free() pair of calls. This is guaranteed by the free()
// operation which allocates a larger tree if the current one becomes
// to small.
mapping_t *
mapdb_t::insert(mapping_t *parent,
space_t *space,
vm_offset_t va,
vm_size_t size,
mapping_type_t type)
{
assert(type == Map_mem); // we don't yet support Map_io
mapping_tree_t *t = parent->tree();
// We cannot continue if the last array entry is not free. This
// only happens if an earlier call to free() with this mapping tree
// couldn't allocate a bigger array. In this case, signal an
// out-of-memory condition.
if (! t->mappings()[t->number_of_entries() - 1].unused())
return nullptr;
// If the parent mapping already has the maximum depth, we cannot
// insert a child.
if (parent->data()->depth == Depth_max)
return nullptr;
mapping_t *insert = 0;
bool
found_free_entry = false,
need_to_move = false;
mapping_t temp;
// Find a free entry in the array encoding the tree, and find the
// insertion point for the new entry. These two entries might not
// be equivalent, so we may need to move entries backwards in the
// array. In this implementation, we move entries as we traverse
// the array, instead of doing one big memmove
for (mapping_t *m = parent + 1;
m < t->mappings() + t->number_of_entries();
m++)
{
if (m->unused())
{
// We found a free entry in the tree -- allocate it.
found_free_entry = true;
t->_count += 1;
// Did we find an empty element != the end tag?
if (m->data()->depth == Depth_empty)
{
t->_empty_count -= 1;
}
// Else we have found the end tag. If there is another
// array entry left, apply a new end tag to the array
else if (m + 1 < t->mappings() + t->number_of_entries())
{
(m + 1)->data()->depth = Depth_end;
}
// if we haven't identified a place for inserting the new
// element, this is it.
if (! need_to_move)
insert = m;
}
else if (! need_to_move
&& m->data()->depth <= parent->data()->depth)
{
// we found a non-descendant of ourselves -- need to make
// space for new child
need_to_move = true;
insert = m;
temp = *insert;
continue;
}
if (need_to_move)
{
// replace *m with temp (which used to be *(m - 1); but
// *(m - 1) has since been overwritten), and load temp with
// the old value of *m
mapping_t temp2;
temp2 = *m;
*m = temp;
temp = temp2;
}
if (found_free_entry)
break;
}
assert(insert && found_free_entry);
// found a place to insert new child.
insert->data()->depth = mapping_depth_t(parent->data()->depth + 1);
insert->data()->address = va >> PAGE_SHIFT;
insert->data()->space = space->space();
insert->data()->size = (size == SUPERPAGE_SIZE);
return insert;
} // insert()
#line 561 "mapping.cpp"
mapping_t *
mapdb_t::lookup(space_t *space,
vm_offset_t va,
mapping_type_t type)
{
vm_offset_t phys = space->virt_to_phys(va);
if (phys == 0xffffffff)
return nullptr;
mapping_tree_t *t;
// get and lock the tree.
// XXX For now, use a simple lock with helping. Later
// unify locking with our request scheme.
physframe[phys >> PAGE_SHIFT].lock.lock();
t = physframe[phys >> PAGE_SHIFT].tree;
assert(t);
mapping_t *m;
for (m = t->mappings();
m->data()->depth != Depth_end
&& m < t->mappings() + t->number_of_entries();
m++)
{
if (m->data()->space == space->space()
&& m->data()->address == va >> PAGE_SHIFT)
{
// found!
return m;
}
}
// not found -- unlock tree
physframe[phys >> PAGE_SHIFT].lock.clear();
return nullptr;
} // lookup()
#line 602 "mapping.cpp"
void
mapdb_t::free(mapping_t* mapping_of_tree)
{
mapping_tree_t *t = mapping_of_tree->tree();
// We assume that the zeroth mapping of the tree is a sigma0
// mapping, that is, its virtual address == the page's physical
// address.
vm_offset_t phys_pno = t->mappings()[0].data()->address;
// We are the owner of the tree lock.
assert(physframe[phys_pno].lock.lock_owner() == current());
// Before we unlock the tree, we need to make sure that there is
// room for at least one new mapping. In particular, this means
// that the last entry of the array encoding the tree must be free.
// (1) When we use up less than a quarter of all entries of the
// array encoding the tree, copy to a smaller tree. Otherwise, (2)
// if the last entry is free, do nothing. Otherwise, (3) if less
// than 3/4 of the entries are used, compress the tree. Otherwise,
// (4) copy to a larger tree.
bool maybe_out_of_memory = false;
do // (this is not actually a loop, just a block we can "break" out of)
{
// (1) Do we need to allocate a smaller tree?
if (t->_size_id > 0 // must not be smallest size
&& (t->_count << 2) < t->number_of_entries())
{
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t *>
(allocator_for_treesize[t->_size_id - 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id - 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
break;
}
}
// (2) Is last entry is free?
if (t->mappings()[t->number_of_entries() - 1].unused())
break; // OK, last entry is free.
// Last entry is not free -- either compress current array
// (i.e., move free entries to end of array), or allocate bigger
// array.
// (3) Should we compress the tree?
// We also try to compress if we cannot allocate a bigger
// tree because there is no bigger tree size.
if (t->_count < (t->number_of_entries() >> 2)
+ (t->number_of_entries() >> 1)
|| t->_size_id == Size_id_max) // cannot enlarge?
{
if (t->_size_id == Size_id_max)
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
break;
}
// (4) OK, allocate a bigger array.
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[t->_size_id + 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id + 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
}
else
{
// out of memory -- just do tree compression and hope that helps.
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
}
}
while (false);
// The last entry of the tree should now be free -- exept if we're
// out of memory.
assert(t->mappings()[t->number_of_entries() - 1].unused()
|| maybe_out_of_memory);
// Unlock tree.
physframe[phys_pno].lock.clear();
} // free()
#line 719 "mapping.cpp"
// Delete mappings from a tree. This is easy to do: We just have to
// iterate over the array encoding the tree.
bool
mapdb_t::flush(mapping_t *m, bool me_too)
{
mapping_tree_t *t = m->tree();
mapping_t *start_of_deletions = m;
unsigned m_depth = m->data()->depth;
unsigned deleted = 0, empty_elems_passed = 0;
if (me_too)
{
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
else
start_of_deletions++;
m++;
for (;
m < t->mappings() + t->number_of_entries()
&& m->data()->depth != Depth_end;
m++)
{
if (unsigned (m->data()->depth) <= m_depth)
{
// Found another data element -- stop deleting. Since we
// created holes in the tree representation, account for it.
t->_empty_count += deleted;
return true;
}
if (m->data()->depth == Depth_empty)
{
empty_elems_passed++;
continue;
}
// Delete the element.
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
// We deleted stuff at the end of the array -- move end tag
if (start_of_deletions < t->mappings() + t->number_of_entries())
{
start_of_deletions->data()->depth = Depth_end;
// also, reduce number of free entries
t->_empty_count -= empty_elems_passed;
}
return true;
} // flush()
#line 778 "mapping.cpp"
void
mapdb_t::grant(mapping_t *m, space_t *new_space, vm_offset_t va)
{
m->data()->space = new_space->space();
m->data()->address = va >> PAGE_SHIFT;
} // grant()

View File

@@ -0,0 +1,155 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef mapping_h
#define mapping_h
#line 2 "mapping.cpp"
#include <flux/x86/types.h> // for vm_offset_t, vm_size_t
#line 4 "mapping.cpp"
#include "space.h" // for space_index_t
//
// INTERFACE definition follows
//
#line 7 "mapping.cpp"
class mapping_tree_t; // forward decls
#line 9 "mapping.cpp"
struct mapping_s;
#line 26 "mapping.cpp"
class kmem_slab_t;
#line 28 "mapping.cpp"
struct physframe_data;
#line 5 "mapping.cpp"
enum mapping_type_t { Map_mem = 0, Map_io };
#line 10 "mapping.cpp"
//
// class mapping_t
//
class mapping_t
{
friend class mapdb_t;
friend class mapping_tree_t;
friend class jdb;
// CREATORS
mapping_t(const mapping_t&); // this constructor is undefined.
// DATA
char _data[5];
public:
#line 224 "mapping.cpp"
space_index_t
space();
#line 231 "mapping.cpp"
vm_offset_t
vaddr();
#line 238 "mapping.cpp"
vm_size_t
size();
#line 248 "mapping.cpp"
mapping_type_t
type();
#line 283 "mapping.cpp"
//
// more of class mapping_t
//
mapping_t *
parent();
#line 307 "mapping.cpp"
mapping_t *
next_iter();
#line 332 "mapping.cpp"
mapping_t *
next_child(mapping_t *parent);
private:
#line 213 "mapping.cpp"
mapping_t();
#line 217 "mapping.cpp"
mapping_s *
data();
#line 256 "mapping.cpp"
bool
unused();
#line 262 "mapping.cpp"
mapping_tree_t *
tree();
} __attribute__((packed));
#line 29 "mapping.cpp"
//
// class mapdb_t: The mapping database
//
class mapdb_t
{
friend class jdb;
public:
enum { Size_factor = 4,
Size_id_max = 8 /* can be up to 15 (4 bits) */ };
private:
// DATA
physframe_data *physframe;
kmem_slab_t *allocator_for_treesize[Size_id_max + 1];
public:
#line 399 "mapping.cpp"
mapdb_t();
#line 450 "mapping.cpp"
// insert a new mapping entry with the given values as child of
// "parent" After locating the right place for the new entry, it will
// be stored there (if this place is empty) or the following entries
// moved by one entry.
// We assume that there is at least one free entry at the end of the
// array so that at least one insert() operation can succeed between a
// lock()/free() pair of calls. This is guaranteed by the free()
// operation which allocates a larger tree if the current one becomes
// to small.
mapping_t *
insert(mapping_t *parent,
space_t *space,
vm_offset_t va,
vm_size_t size,
mapping_type_t type);
#line 562 "mapping.cpp"
mapping_t *
lookup(space_t *space,
vm_offset_t va,
mapping_type_t type);
#line 603 "mapping.cpp"
void
free(mapping_t* mapping_of_tree);
#line 720 "mapping.cpp"
// Delete mappings from a tree. This is easy to do: We just have to
// iterate over the array encoding the tree.
bool
flush(mapping_t *m, bool me_too);
#line 779 "mapping.cpp"
void
grant(mapping_t *m, space_t *new_space, vm_offset_t va);
};
#endif // mapping_h

View File

@@ -0,0 +1,101 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef mapping_i_h
#define mapping_i_h
#include "mapping.h"
#line 148 "mapping.cpp"
#include <assert.h>
#line 150 "mapping.cpp"
#include <string.h>
#line 385 "mapping.cpp"
//
// class mapdb
//
#include "lock.h"
#line 391 "mapping.cpp"
#include "kmem_slab.h"
//
// INTERFACE internal declaration follows
//
#line 155 "mapping.cpp"
// For implementation of mapping_t functions, we need mapping_tree_t.
//
// class mapping_tree_t
//
class mapping_tree_t
{
friend class mapping_t;
friend class mapdb_t;
friend class jdb;
// DATA
unsigned _count: 16;
unsigned _size_id: 4;
unsigned _empty_count: 11;
unsigned _unused: 1; // make this 32 bits to avoid a compiler bug
mapping_t _mappings[0] __attribute__((packed));
public:
#line 347 "mapping.cpp"
// helpers
//
// class mapping_tree_t
//
// This function copies the elements of mapping tree src to mapping
// tree dst, ignoring empty elements (that is, compressing the
// source tree. In-place compression is supported.
static void
copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src);
private:
#line 177 "mapping.cpp"
// public routines with inline implementations
unsigned
number_of_entries() const;
#line 186 "mapping.cpp"
mapping_t *
mappings();
} __attribute__((packed));
#line 191 "mapping.cpp"
// Define (otherwise private) stuff needed by public inline
// functions.
enum mapping_depth_t
{
Depth_sigma0_mapping = 0, Depth_max = 253,
Depth_empty = 254, Depth_end = 255
};
#line 200 "mapping.cpp"
struct mapping_s
{
unsigned space:11;
unsigned size:1;
unsigned address:20;
mapping_depth_t depth:8;
unsigned do_not_touch: 24; // make this 64 bits, and make sure the
// compiler never touches memory after the
// real data
};
#line 392 "mapping.cpp"
struct physframe_data {
mapping_tree_t *tree;
helping_lock_t lock;
};
#endif // mapping_i_h

View File

@@ -0,0 +1,652 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "mapping_inline.h"
#include "mapping_inline_i.h"
//
// IMPLEMENTATION follows
//
#line 48 "mapping.cpp"
// The mapping database.
// This implementation encodes mapping trees in very compact arrays of
// fixed sizes, prefixed by a tree header (mapping_tree_t). Array
// sizes can vary from 4 mappings to 4<<15 mappings. For each size,
// we set up a slab allocator. To grow or shrink the size of an
// array, we have to allocate a larger or smaller tree from the
// corresponding allocator and then copy the array elements.
//
// The array elements (mapping_t) contain a tree depth element. This
// depth and the relative position in the array is all information we
// need to derive tree structure information. Here is an example:
//
// array
// element depth
// number value comment
// --------------------------
// 0 0 Sigma0 mapping
// 1 1 child of element #0 with depth 0
// 2 2 child of element #1 with depth 1
// 3 2 child of element #1 with depth 1
// 4 3 child of element #3 with depth 2
// 5 2 child of element #1 with depth 1
// 6 3 child of element #5 with depth 2
// 7 1 child of element #0 with depth 0
//
// This array is a pre-order encoding of the following tree:
//
// 0
// / \
// 1 7
// / | \
// 2 3 5
// | |
// 4 6
// IDEAS for enhancing this implementation:
// We often have to find a tree header corresponding to a mapping.
// Currently, we do this by iterating backwards over the array
// containing the mappings until we find the Sigma0 mapping, from
// whose address we can compute the address of the tree header. If
// this becomes a problem, we could add one more byte to the mappings
// with a hint (negative array offset) where to find the sigma0
// mapping. (If the hint value overflows, just iterate using the hint
// value of the mapping we find with the first hint value.) Another
// idea (from Adam) would be to just look up the tree header by using
// the physical address from the page-table lookup, but we would need
// to change the interface of the mapping database for that (pass in
// the physical address at all times), or we would have to include the
// physical address (or just the address of the tree header) in the
// mapdb_t-user-visible mapping_t (which could be different from the
// internal tree representation). (XXX: Implementing one of these
// ideas is probably worthwile doing!)
// Instead of copying whole trees around when they grow or shrink a
// lot, or copying parts of trees when inserting an element, we could
// give up the array representation and add a "next" pointer to the
// elements -- that is, keep the tree of mappings in a
// pre-order-encoded singly-linked list (credits to: Christan Szmajda
// and Adam Wiggins). 24 bits would probably be enough to encode that
// pointer. Disadvantages: Mapping entries would be larger, and the
// cache-friendly space-locality of tree entries would be lost.
// The current handling of superpages sucks rocks both in this module
// and in our user, ipc_map.cc. We could support multiple page sizes
// by not using a physframe[] array only for the largest page size.
// (Entries of that array point to the top-level mappings -- sigma0
// mappings.) Mapping-tree entries would then either be regular
// mappings or pointers to an array of mappings of the next-smaller
// size. (credits: Christan Szmajda)
//
// physframe[]
// -------------------------------
// | | | | | | | | | | | | | | | | array of ptr to 4M mapping_tree_t's
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t *or* ptr to array of ptr to 4K trees
// | | e.g.
// | ----------------|
// | | v array of ptr to 4M mapping_tree_t's
// --------------- -------------------------------
// | | | | | | | | | | | | | | | |
// ---|---------------------------
// |
// v a mapping_tree_t
// ---------------
// | | tree header
// |-------------|
// | | mapping_t
// | |
// | |
// | |
// ---------------
//-
#line 151 "mapping.cpp"
#ifndef offsetof // should be defined in stddef.h, but isn't
#line 153 "mapping.cpp"
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#line 154 "mapping.cpp"
#endif
#line 261 "mapping.cpp"
mapping_tree_t *
mapping_t::tree()
{
mapping_t *m = this;
while (m->data()->depth > Depth_sigma0_mapping)
{
// jump in bigger steps if this is not a free mapping
if (! m->unused())
{
m -= m->data()->depth;
continue;
}
m--;
}
return reinterpret_cast<mapping_tree_t *>
(reinterpret_cast<char *>(m) - offsetof(mapping_tree_t, _mappings));
}
#line 282 "mapping.cpp"
//
// more of class mapping_t
//
mapping_t *
mapping_t::parent()
{
if (data()->depth <= Depth_sigma0_mapping)
{
// Sigma0 mappings don't have a parent.
return nullptr;
}
// Iterate over mapping entries of this tree backwards until we find
// an entry with a depth smaller than ours. (We assume here that
// "special" depths (empty, end) are larger than Depth_max.)
mapping_t *m = this - 1;
while (m->data()->depth >= data()->depth)
m--;
return m;
}
#line 306 "mapping.cpp"
mapping_t *
mapping_t::next_iter()
{
mapping_tree_t *t = tree();
mapping_t *last_in_tree = t->mappings() + t->number_of_entries() - 1;
mapping_t *m = this;
// Look for a valid element in the tree structure.
while (m != last_in_tree)
{
m++;
if (! m->unused())
return m; // Found a valid entry!
// Don't iterate to end of tree if this is the last tree entry.
if (m->data()->depth == Depth_end)
return 0;
}
// Couldn't find a non-empty element behind ourselves in the tree
// structure.
return 0;
}
#line 331 "mapping.cpp"
mapping_t *
mapping_t::next_child(mapping_t *parent)
{
// Find the next valid entry in the tree structure.
mapping_t *m = next_iter();
// If we didn't find an entry, or if the entry cannot be a child of
// "parent", return nullptr
if (m == 0
|| m->data()->depth <= parent->data()->depth)
return nullptr;
return m; // Found!
}
#line 346 "mapping.cpp"
// helpers
//
// class mapping_tree_t
//
// This function copies the elements of mapping tree src to mapping
// tree dst, ignoring empty elements (that is, compressing the
// source tree. In-place compression is supported.
void
mapping_tree_t::copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src)
{
dst->_count = 0;
dst->_empty_count = 0;
mapping_t *d = dst->mappings();
for (mapping_t *s = src->mappings();
s < src->mappings() + src->number_of_entries();
s++)
{
if (s->unused()) // entry free
{
if (s->data()->depth == Depth_end)
break;
continue;
}
*d++ = *s;
dst->_count += 1;
}
assert (dst->_count == src->_count);
assert (d < dst->mappings() + dst->number_of_entries());
d->data()->depth = Depth_end;
dst->mappings()[dst->number_of_entries() - 1].data()->depth = Depth_end;
} // copy_compact_tree()
#line 397 "mapping.cpp"
mapdb_t::mapdb_t()
{
vm_offset_t page_number = kmem::info()->main_memory.high / PAGE_SIZE + 1;
// allocate physframe array
check ( physframe = reinterpret_cast<physframe_data *>
(kmem::alloc(page_number * sizeof(physframe_data))) );
memset(physframe, 0, page_number * sizeof(physframe_data));
// create a slab for each mapping tree size
for (int slab_number = 0;
slab_number <= Size_id_max;
slab_number++ )
{
unsigned elem_size =
(Size_factor << slab_number) * sizeof(mapping_t)
+ sizeof(mapping_tree_t);
allocator_for_treesize[slab_number] =
new kmem_slab_t(((PAGE_SIZE / elem_size) < 40
? 8*PAGE_SIZE : PAGE_SIZE),
elem_size, 1);
}
// create a sigma0 mapping for all physical pages
for (unsigned page_id = 0; page_id < page_number; page_id++)
{
mapping_tree_t *t;
check( (t = physframe[page_id].tree
= reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[0]->alloc())) );
t->_count = 1; // 1 valid mapping
t->_size_id = 0; // size is equal to Size_factor << 0
t->_empty_count = 0; // no gaps in tree representation
t->mappings()[0].data()->depth = Depth_sigma0_mapping;
t->mappings()[0].data()->address = page_id;
t->mappings()[0].data()->space = config::sigma0_taskno;
t->mappings()[0].data()->size = 0;
t->mappings()[1].data()->depth = Depth_end;
// We also always set the end tag on last entry so that we can
// check whether it has been overwritten.
t->mappings()[t->number_of_entries() - 1].data()->depth = Depth_end;
}
} // mapdb_t()
#line 448 "mapping.cpp"
// insert a new mapping entry with the given values as child of
// "parent" After locating the right place for the new entry, it will
// be stored there (if this place is empty) or the following entries
// moved by one entry.
// We assume that there is at least one free entry at the end of the
// array so that at least one insert() operation can succeed between a
// lock()/free() pair of calls. This is guaranteed by the free()
// operation which allocates a larger tree if the current one becomes
// to small.
mapping_t *
mapdb_t::insert(mapping_t *parent,
space_t *space,
vm_offset_t va,
vm_size_t size,
mapping_type_t type)
{
assert(type == Map_mem); // we don't yet support Map_io
mapping_tree_t *t = parent->tree();
// We cannot continue if the last array entry is not free. This
// only happens if an earlier call to free() with this mapping tree
// couldn't allocate a bigger array. In this case, signal an
// out-of-memory condition.
if (! t->mappings()[t->number_of_entries() - 1].unused())
return nullptr;
// If the parent mapping already has the maximum depth, we cannot
// insert a child.
if (parent->data()->depth == Depth_max)
return nullptr;
mapping_t *insert = 0;
bool
found_free_entry = false,
need_to_move = false;
mapping_t temp;
// Find a free entry in the array encoding the tree, and find the
// insertion point for the new entry. These two entries might not
// be equivalent, so we may need to move entries backwards in the
// array. In this implementation, we move entries as we traverse
// the array, instead of doing one big memmove
for (mapping_t *m = parent + 1;
m < t->mappings() + t->number_of_entries();
m++)
{
if (m->unused())
{
// We found a free entry in the tree -- allocate it.
found_free_entry = true;
t->_count += 1;
// Did we find an empty element != the end tag?
if (m->data()->depth == Depth_empty)
{
t->_empty_count -= 1;
}
// Else we have found the end tag. If there is another
// array entry left, apply a new end tag to the array
else if (m + 1 < t->mappings() + t->number_of_entries())
{
(m + 1)->data()->depth = Depth_end;
}
// if we haven't identified a place for inserting the new
// element, this is it.
if (! need_to_move)
insert = m;
}
else if (! need_to_move
&& m->data()->depth <= parent->data()->depth)
{
// we found a non-descendant of ourselves -- need to make
// space for new child
need_to_move = true;
insert = m;
temp = *insert;
continue;
}
if (need_to_move)
{
// replace *m with temp (which used to be *(m - 1); but
// *(m - 1) has since been overwritten), and load temp with
// the old value of *m
mapping_t temp2;
temp2 = *m;
*m = temp;
temp = temp2;
}
if (found_free_entry)
break;
}
assert(insert && found_free_entry);
// found a place to insert new child.
insert->data()->depth = mapping_depth_t(parent->data()->depth + 1);
insert->data()->address = va >> PAGE_SHIFT;
insert->data()->space = space->space();
insert->data()->size = (size == SUPERPAGE_SIZE);
return insert;
} // insert()
#line 561 "mapping.cpp"
mapping_t *
mapdb_t::lookup(space_t *space,
vm_offset_t va,
mapping_type_t type)
{
vm_offset_t phys = space->virt_to_phys(va);
if (phys == 0xffffffff)
return nullptr;
mapping_tree_t *t;
// get and lock the tree.
// XXX For now, use a simple lock with helping. Later
// unify locking with our request scheme.
physframe[phys >> PAGE_SHIFT].lock.lock();
t = physframe[phys >> PAGE_SHIFT].tree;
assert(t);
mapping_t *m;
for (m = t->mappings();
m->data()->depth != Depth_end
&& m < t->mappings() + t->number_of_entries();
m++)
{
if (m->data()->space == space->space()
&& m->data()->address == va >> PAGE_SHIFT)
{
// found!
return m;
}
}
// not found -- unlock tree
physframe[phys >> PAGE_SHIFT].lock.clear();
return nullptr;
} // lookup()
#line 602 "mapping.cpp"
void
mapdb_t::free(mapping_t* mapping_of_tree)
{
mapping_tree_t *t = mapping_of_tree->tree();
// We assume that the zeroth mapping of the tree is a sigma0
// mapping, that is, its virtual address == the page's physical
// address.
vm_offset_t phys_pno = t->mappings()[0].data()->address;
// We are the owner of the tree lock.
assert(physframe[phys_pno].lock.lock_owner() == current());
// Before we unlock the tree, we need to make sure that there is
// room for at least one new mapping. In particular, this means
// that the last entry of the array encoding the tree must be free.
// (1) When we use up less than a quarter of all entries of the
// array encoding the tree, copy to a smaller tree. Otherwise, (2)
// if the last entry is free, do nothing. Otherwise, (3) if less
// than 3/4 of the entries are used, compress the tree. Otherwise,
// (4) copy to a larger tree.
bool maybe_out_of_memory = false;
do // (this is not actually a loop, just a block we can "break" out of)
{
// (1) Do we need to allocate a smaller tree?
if (t->_size_id > 0 // must not be smallest size
&& (t->_count << 2) < t->number_of_entries())
{
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t *>
(allocator_for_treesize[t->_size_id - 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id - 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
break;
}
}
// (2) Is last entry is free?
if (t->mappings()[t->number_of_entries() - 1].unused())
break; // OK, last entry is free.
// Last entry is not free -- either compress current array
// (i.e., move free entries to end of array), or allocate bigger
// array.
// (3) Should we compress the tree?
// We also try to compress if we cannot allocate a bigger
// tree because there is no bigger tree size.
if (t->_count < (t->number_of_entries() >> 2)
+ (t->number_of_entries() >> 1)
|| t->_size_id == Size_id_max) // cannot enlarge?
{
if (t->_size_id == Size_id_max)
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
break;
}
// (4) OK, allocate a bigger array.
mapping_tree_t *new_t =
reinterpret_cast<mapping_tree_t*>
(allocator_for_treesize[t->_size_id + 1]->alloc());
if (new_t)
{
// XXX should be asserted by allocator:
new_t->_size_id = t->_size_id + 1;
new_t->mappings()[new_t->number_of_entries() - 1].data()->depth
= Depth_end;
mapping_tree_t::copy_compact_tree(new_t, t);
// Register new tree.
physframe[phys_pno].tree = new_t;
allocator_for_treesize[t->_size_id]->free(t);
t = new_t;
}
else
{
// out of memory -- just do tree compression and hope that helps.
maybe_out_of_memory = true;
mapping_tree_t::copy_compact_tree(t, t); // in-place compression
}
}
while (false);
// The last entry of the tree should now be free -- exept if we're
// out of memory.
assert(t->mappings()[t->number_of_entries() - 1].unused()
|| maybe_out_of_memory);
// Unlock tree.
physframe[phys_pno].lock.clear();
} // free()
#line 719 "mapping.cpp"
// Delete mappings from a tree. This is easy to do: We just have to
// iterate over the array encoding the tree.
bool
mapdb_t::flush(mapping_t *m, bool me_too)
{
mapping_tree_t *t = m->tree();
mapping_t *start_of_deletions = m;
unsigned m_depth = m->data()->depth;
unsigned deleted = 0, empty_elems_passed = 0;
if (me_too)
{
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
else
start_of_deletions++;
m++;
for (;
m < t->mappings() + t->number_of_entries()
&& m->data()->depth != Depth_end;
m++)
{
if (unsigned (m->data()->depth) <= m_depth)
{
// Found another data element -- stop deleting. Since we
// created holes in the tree representation, account for it.
t->_empty_count += deleted;
return true;
}
if (m->data()->depth == Depth_empty)
{
empty_elems_passed++;
continue;
}
// Delete the element.
m->data()->depth = Depth_empty;
t->_count -= 1;
deleted++;
}
// We deleted stuff at the end of the array -- move end tag
if (start_of_deletions < t->mappings() + t->number_of_entries())
{
start_of_deletions->data()->depth = Depth_end;
// also, reduce number of free entries
t->_empty_count -= empty_elems_passed;
}
return true;
} // flush()
#line 778 "mapping.cpp"
void
mapdb_t::grant(mapping_t *m, space_t *new_space, vm_offset_t va)
{
m->data()->space = new_space->space();
m->data()->address = va >> PAGE_SHIFT;
} // grant()

View File

@@ -0,0 +1,231 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef mapping_inline_h
#define mapping_inline_h
#line 2 "mapping.cpp"
#include <flux/x86/types.h> // for vm_offset_t, vm_size_t
#line 4 "mapping.cpp"
#include "space.h" // for space_index_t
//
// INTERFACE definition follows
//
#line 7 "mapping.cpp"
class mapping_tree_t; // forward decls
#line 9 "mapping.cpp"
struct mapping_s;
#line 26 "mapping.cpp"
class kmem_slab_t;
#line 28 "mapping.cpp"
struct physframe_data;
#line 5 "mapping.cpp"
enum mapping_type_t { Map_mem = 0, Map_io };
#line 10 "mapping.cpp"
//
// class mapping_t
//
class mapping_t
{
friend class mapdb_t;
friend class mapping_tree_t;
friend class jdb;
// CREATORS
mapping_t(const mapping_t&); // this constructor is undefined.
// DATA
char _data[5];
public:
#line 224 "mapping.cpp"
inline space_index_t
space();
#line 231 "mapping.cpp"
inline vm_offset_t
vaddr();
#line 238 "mapping.cpp"
inline vm_size_t
size();
#line 248 "mapping.cpp"
inline mapping_type_t
type();
#line 283 "mapping.cpp"
//
// more of class mapping_t
//
mapping_t *
parent();
#line 307 "mapping.cpp"
mapping_t *
next_iter();
#line 332 "mapping.cpp"
mapping_t *
next_child(mapping_t *parent);
private:
#line 213 "mapping.cpp"
inline mapping_t();
#line 217 "mapping.cpp"
inline mapping_s *
data();
#line 256 "mapping.cpp"
inline bool
unused();
#line 262 "mapping.cpp"
mapping_tree_t *
tree();
} __attribute__((packed));
#line 29 "mapping.cpp"
//
// class mapdb_t: The mapping database
//
class mapdb_t
{
friend class jdb;
public:
enum { Size_factor = 4,
Size_id_max = 8 /* can be up to 15 (4 bits) */ };
private:
// DATA
physframe_data *physframe;
kmem_slab_t *allocator_for_treesize[Size_id_max + 1];
public:
#line 399 "mapping.cpp"
mapdb_t();
#line 450 "mapping.cpp"
// insert a new mapping entry with the given values as child of
// "parent" After locating the right place for the new entry, it will
// be stored there (if this place is empty) or the following entries
// moved by one entry.
// We assume that there is at least one free entry at the end of the
// array so that at least one insert() operation can succeed between a
// lock()/free() pair of calls. This is guaranteed by the free()
// operation which allocates a larger tree if the current one becomes
// to small.
mapping_t *
insert(mapping_t *parent,
space_t *space,
vm_offset_t va,
vm_size_t size,
mapping_type_t type);
#line 562 "mapping.cpp"
mapping_t *
lookup(space_t *space,
vm_offset_t va,
mapping_type_t type);
#line 603 "mapping.cpp"
void
free(mapping_t* mapping_of_tree);
#line 720 "mapping.cpp"
// Delete mappings from a tree. This is easy to do: We just have to
// iterate over the array encoding the tree.
bool
flush(mapping_t *m, bool me_too);
#line 779 "mapping.cpp"
void
grant(mapping_t *m, space_t *new_space, vm_offset_t va);
};
//
// IMPLEMENTATION of inline functions (and needed classes)
//
#line 191 "mapping.cpp"
// Define (otherwise private) stuff needed by public inline
// functions.
enum mapping_depth_t
{
Depth_sigma0_mapping = 0, Depth_max = 253,
Depth_empty = 254, Depth_end = 255
};
#line 200 "mapping.cpp"
struct mapping_s
{
unsigned space:11;
unsigned size:1;
unsigned address:20;
mapping_depth_t depth:8;
unsigned do_not_touch: 24; // make this 64 bits, and make sure the
// compiler never touches memory after the
// real data
};
#line 215 "mapping.cpp"
inline mapping_s *
mapping_t::data()
{
return reinterpret_cast<mapping_s*>(_data);
}
#line 222 "mapping.cpp"
inline space_index_t
mapping_t::space()
{
return space_index_t(data()->space);
}
#line 229 "mapping.cpp"
inline vm_offset_t
mapping_t::vaddr()
{
return (data()->address << PAGE_SHIFT);
}
#line 236 "mapping.cpp"
inline vm_size_t
mapping_t::size()
{
if ( data()->size )
return SUPERPAGE_SIZE;
else
return PAGE_SIZE;
}
#line 246 "mapping.cpp"
inline mapping_type_t
mapping_t::type()
{
// return data()->type;;
return Map_mem;
}
#endif // mapping_inline_h

View File

@@ -0,0 +1,118 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#ifndef mapping_inline_i_h
#define mapping_inline_i_h
#include "mapping_inline.h"
#line 148 "mapping.cpp"
#include <assert.h>
#line 150 "mapping.cpp"
#include <string.h>
#line 385 "mapping.cpp"
//
// class mapdb
//
#include "lock.h"
#line 391 "mapping.cpp"
#include "kmem_slab.h"
//
// INTERFACE internal declaration follows
//
#line 155 "mapping.cpp"
// For implementation of mapping_t functions, we need mapping_tree_t.
//
// class mapping_tree_t
//
class mapping_tree_t
{
friend class mapping_t;
friend class mapdb_t;
friend class jdb;
// DATA
unsigned _count: 16;
unsigned _size_id: 4;
unsigned _empty_count: 11;
unsigned _unused: 1; // make this 32 bits to avoid a compiler bug
mapping_t _mappings[0] __attribute__((packed));
public:
#line 347 "mapping.cpp"
// helpers
//
// class mapping_tree_t
//
// This function copies the elements of mapping tree src to mapping
// tree dst, ignoring empty elements (that is, compressing the
// source tree. In-place compression is supported.
static void
copy_compact_tree(mapping_tree_t *dst, mapping_tree_t *src);
private:
#line 177 "mapping.cpp"
// public routines with inline implementations
inline unsigned
number_of_entries() const;
#line 186 "mapping.cpp"
inline mapping_t *
mappings();
} __attribute__((packed));
#line 392 "mapping.cpp"
struct physframe_data {
mapping_tree_t *tree;
helping_lock_t lock;
};
//
// IMPLEMENTATION of inline functions follows
//
#line 211 "mapping.cpp"
inline mapping_t::mapping_t()
{}
#line 254 "mapping.cpp"
inline bool
mapping_t::unused()
{
return (data()->depth > Depth_max);
}
#line 176 "mapping.cpp"
// public routines with inline implementations
inline unsigned
mapping_tree_t::number_of_entries() const
{
return mapdb_t::Size_factor << _size_id;
}
#line 184 "mapping.cpp"
inline mapping_t *
mapping_tree_t::mappings()
{
return & _mappings[0];
}
#endif // mapping_inline_i_h

View File

@@ -0,0 +1,17 @@
// AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*-
#include "multifile.h"
#include "multifile_i.h"
//
// IMPLEMENTATION follows
//
#line 8 "multifile1.cpp"
void
Foo::bar ()
{}

Some files were not shown because too many files have changed in this diff Show More