llrb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.gitmodules +4 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +56 -0
- data/README.md +311 -0
- data/Rakefile +30 -0
- data/bin/bm_app_fib +41 -0
- data/bin/bm_empty_method +33 -0
- data/bin/bm_loop_while +27 -0
- data/bin/bm_plus +33 -0
- data/bin/console +14 -0
- data/bin/loop_while.rb +5 -0
- data/bin/setup +8 -0
- data/ext/llrb/cfg.h +124 -0
- data/ext/llrb/compiler.c +987 -0
- data/ext/llrb/compiler/funcs.h +164 -0
- data/ext/llrb/compiler/stack.h +43 -0
- data/ext/llrb/cruby.h +42 -0
- data/ext/llrb/cruby/ccan/build_assert/build_assert.h +40 -0
- data/ext/llrb/cruby/ccan/check_type/check_type.h +63 -0
- data/ext/llrb/cruby/ccan/container_of/container_of.h +142 -0
- data/ext/llrb/cruby/ccan/list/list.h +773 -0
- data/ext/llrb/cruby/ccan/str/str.h +16 -0
- data/ext/llrb/cruby/internal.h +1774 -0
- data/ext/llrb/cruby/iseq.h +252 -0
- data/ext/llrb/cruby/method.h +213 -0
- data/ext/llrb/cruby/node.h +520 -0
- data/ext/llrb/cruby/probes_helper.h +43 -0
- data/ext/llrb/cruby/ruby_assert.h +54 -0
- data/ext/llrb/cruby/ruby_atomic.h +233 -0
- data/ext/llrb/cruby/thread_pthread.h +54 -0
- data/ext/llrb/cruby/vm_core.h +1646 -0
- data/ext/llrb/cruby/vm_debug.h +37 -0
- data/ext/llrb/cruby/vm_exec.h +182 -0
- data/ext/llrb/cruby/vm_opts.h +57 -0
- data/ext/llrb/cruby_extra/id.h +220 -0
- data/ext/llrb/cruby_extra/insns.inc +113 -0
- data/ext/llrb/cruby_extra/insns_info.inc +796 -0
- data/ext/llrb/cruby_extra/probes.h +80 -0
- data/ext/llrb/extconf.rb +102 -0
- data/ext/llrb/llrb.c +148 -0
- data/ext/llrb/optimizer.cc +118 -0
- data/ext/llrb/parser.c +191 -0
- data/ext/llrb/profiler.c +336 -0
- data/ext/llrb_insn_checkkeyword.c +20 -0
- data/ext/llrb_insn_checkmatch.c +28 -0
- data/ext/llrb_insn_concatarray.c +23 -0
- data/ext/llrb_insn_concatstrings.c +21 -0
- data/ext/llrb_insn_defined.c +9 -0
- data/ext/llrb_insn_getclassvariable.c +10 -0
- data/ext/llrb_insn_getinstancevariable.c +44 -0
- data/ext/llrb_insn_getlocal.c +14 -0
- data/ext/llrb_insn_getlocal_level0.c +8 -0
- data/ext/llrb_insn_getlocal_level1.c +8 -0
- data/ext/llrb_insn_getspecial.c +14 -0
- data/ext/llrb_insn_invokeblock.c +39 -0
- data/ext/llrb_insn_invokesuper.c +47 -0
- data/ext/llrb_insn_opt_aref.c +25 -0
- data/ext/llrb_insn_opt_aset.c +28 -0
- data/ext/llrb_insn_opt_div.c +32 -0
- data/ext/llrb_insn_opt_eq.c +57 -0
- data/ext/llrb_insn_opt_ge.c +28 -0
- data/ext/llrb_insn_opt_gt.c +38 -0
- data/ext/llrb_insn_opt_le.c +29 -0
- data/ext/llrb_insn_opt_lt.c +38 -0
- data/ext/llrb_insn_opt_ltlt.c +27 -0
- data/ext/llrb_insn_opt_minus.c +36 -0
- data/ext/llrb_insn_opt_mod.c +32 -0
- data/ext/llrb_insn_opt_mult.c +30 -0
- data/ext/llrb_insn_opt_neq.c +103 -0
- data/ext/llrb_insn_opt_plus.c +48 -0
- data/ext/llrb_insn_opt_send_without_block.c +45 -0
- data/ext/llrb_insn_opt_str_freeze.c +12 -0
- data/ext/llrb_insn_putspecialobject.c +23 -0
- data/ext/llrb_insn_send.c +49 -0
- data/ext/llrb_insn_setclassvariable.c +19 -0
- data/ext/llrb_insn_setconstant.c +23 -0
- data/ext/llrb_insn_setinstancevariable.c +48 -0
- data/ext/llrb_insn_setlocal.c +16 -0
- data/ext/llrb_insn_setlocal_level0.c +9 -0
- data/ext/llrb_insn_setlocal_level1.c +10 -0
- data/ext/llrb_insn_setspecial.c +15 -0
- data/ext/llrb_insn_splatarray.c +13 -0
- data/ext/llrb_insn_throw.c +11 -0
- data/ext/llrb_insn_trace.c +37 -0
- data/ext/llrb_push_result.c +14 -0
- data/ext/llrb_self_from_cfp.c +12 -0
- data/ext/llrb_set_pc.c +8 -0
- data/lib/llrb.rb +2 -0
- data/lib/llrb/jit.rb +76 -0
- data/lib/llrb/start.rb +2 -0
- data/lib/llrb/version.rb +3 -0
- data/llrb.gemspec +48 -0
- data/wercker.yml +31 -0
- metadata +227 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
/*
|
2
|
+
* compiler/funcs.h: External function declaration called by JIT-ed code.
|
3
|
+
* This header is used only by compiler.c.
|
4
|
+
* TODO: Automatically generate this from something.
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifndef LLRB_COMPILER_FUNCS_H
|
8
|
+
#define LLRB_COMPILER_FUNCS_H
|
9
|
+
|
10
|
+
#include <string.h>
|
11
|
+
#include "ruby.h"
|
12
|
+
#include "llvm-c/BitReader.h"
|
13
|
+
#include "llvm-c/Linker.h"
|
14
|
+
|
15
|
+
#define LLRB_EXTERN_FUNC_MAX_ARGC 6
|
16
|
+
struct llrb_extern_func {
|
17
|
+
unsigned int return_type; // 0 = void, 32 = 32bit int, 64 = 64bit int
|
18
|
+
unsigned int argc;
|
19
|
+
unsigned int argv[LLRB_EXTERN_FUNC_MAX_ARGC]; // 0 = void, 32 = 32bit int, 64 = 64bit int
|
20
|
+
bool unlimited;
|
21
|
+
const char *name;
|
22
|
+
bool has_bc;
|
23
|
+
};
|
24
|
+
|
25
|
+
// TODO: support 32bit environment
|
26
|
+
static struct llrb_extern_func llrb_extern_funcs[] = {
|
27
|
+
{ 64, 0, { 0 }, false, "rb_hash_new" },
|
28
|
+
{ 64, 1, { 64 }, false, "llrb_insn_opt_str_freeze", true },
|
29
|
+
{ 64, 1, { 64 }, false, "llrb_insn_putspecialobject", true },
|
30
|
+
{ 64, 1, { 64 }, false, "llrb_self_from_cfp", true },
|
31
|
+
{ 64, 1, { 64 }, false, "rb_ary_clear" },
|
32
|
+
{ 64, 1, { 64 }, false, "rb_ary_resurrect" },
|
33
|
+
{ 64, 1, { 64 }, false, "rb_gvar_get" },
|
34
|
+
{ 64, 1, { 64 }, false, "rb_obj_as_string" },
|
35
|
+
{ 64, 1, { 64 }, false, "rb_str_freeze" },
|
36
|
+
{ 64, 1, { 64 }, false, "rb_str_resurrect" },
|
37
|
+
{ 64, 1, { 64 }, true, "llrb_insn_concatstrings", true },
|
38
|
+
{ 64, 1, { 64 }, true, "rb_ary_new_from_args" },
|
39
|
+
{ 0, 2, { 64, 64 }, false, "llrb_insn_setspecial", true },
|
40
|
+
{ 0, 2, { 64, 64 }, false, "llrb_push_result", true },
|
41
|
+
{ 0, 2, { 64, 64 }, false, "llrb_set_pc", true },
|
42
|
+
{ 64, 2, { 64, 32 }, false, "rb_reg_new_ary" },
|
43
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_concatarray", true },
|
44
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_getclassvariable", true },
|
45
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_getlocal_level0", true },
|
46
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_getlocal_level1", true },
|
47
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_getspecial", true },
|
48
|
+
//{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_newarray_max", true },
|
49
|
+
//{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_newarray_min", true },
|
50
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_mult", true },
|
51
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_div", true },
|
52
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_mod", true },
|
53
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_eq", true },
|
54
|
+
{ 64, 6, { 64, 64, 64, 64, 64, 64 }, false, "llrb_insn_opt_neq", true },
|
55
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_le", true },
|
56
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_gt", true },
|
57
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_ge", true },
|
58
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_ltlt", true },
|
59
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_aref", true },
|
60
|
+
{ 64, 3, { 64, 64, 64 }, false, "llrb_insn_opt_aset", true },
|
61
|
+
{ 64, 3, { 64, 64, 64 }, false, "llrb_insn_getinstancevariable", true },
|
62
|
+
{ 0, 4, { 64, 64, 64, 64 }, false, "llrb_insn_setinstancevariable", true },
|
63
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_lt", true },
|
64
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_minus", true },
|
65
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_opt_plus", true },
|
66
|
+
{ 64, 2, { 64, 64 }, false, "llrb_insn_splatarray", true },
|
67
|
+
{ 64, 2, { 64, 64 }, false, "rb_gvar_set" },
|
68
|
+
{ 64, 2, { 64, 64 }, false, "rb_ivar_get" },
|
69
|
+
{ 64, 2, { 64, 64 }, true, "llrb_insn_toregexp" },
|
70
|
+
{ 64, 2, { 64, 64 }, true, "rb_funcall" },
|
71
|
+
{ 0, 3, { 64, 64, 64 }, false, "llrb_insn_setclassvariable", true },
|
72
|
+
{ 0, 3, { 64, 64, 64 }, false, "llrb_insn_setlocal_level0", true },
|
73
|
+
{ 0, 3, { 64, 64, 64 }, false, "llrb_insn_setlocal_level1", true },
|
74
|
+
{ 64, 3, { 64, 64, 64 }, false, "llrb_insn_checkkeyword", true },
|
75
|
+
{ 64, 3, { 64, 64, 64 }, false, "llrb_insn_checkmatch", true },
|
76
|
+
{ 64, 3, { 64, 64, 64 }, false, "llrb_insn_getlocal", true },
|
77
|
+
{ 64, 3, { 64, 64, 64 }, false, "rb_hash_aset" },
|
78
|
+
{ 64, 3, { 64, 64, 64 }, false, "rb_ivar_set" },
|
79
|
+
{ 64, 3, { 64, 64, 64 }, false, "rb_range_new" },
|
80
|
+
{ 0, 4, { 64, 64, 32, 64 }, false, "llrb_insn_trace", true },
|
81
|
+
{ 0, 4, { 64, 64, 64, 64 }, false, "llrb_insn_setconstant", true },
|
82
|
+
{ 0, 4, { 64, 64, 64, 64 }, false, "llrb_insn_setlocal", true },
|
83
|
+
{ 0, 4, { 64, 64, 64, 64 }, false, "llrb_insn_throw", true },
|
84
|
+
{ 64, 4, { 64, 64, 64, 32 }, false, "vm_get_ev_const" },
|
85
|
+
{ 64, 4, { 64, 64, 64, 32 }, true, "llrb_insn_invokeblock", true },
|
86
|
+
{ 64, 4, { 64, 64, 64, 64 }, false, "llrb_insn_defined", true },
|
87
|
+
{ 64, 5, { 64, 64, 64, 64, 32 }, true, "llrb_insn_opt_send_without_block", true },
|
88
|
+
{ 64, 6, { 64, 64, 64, 64, 64, 32 }, true, "llrb_insn_invokesuper", true },
|
89
|
+
{ 64, 6, { 64, 64, 64, 64, 64, 32 }, true, "llrb_insn_send", true },
|
90
|
+
};
|
91
|
+
static size_t llrb_extern_func_num = sizeof(llrb_extern_funcs) / sizeof(struct llrb_extern_func);
|
92
|
+
|
93
|
+
static inline LLVMTypeRef
|
94
|
+
llrb_num_to_type(unsigned int num)
|
95
|
+
{
|
96
|
+
switch (num) {
|
97
|
+
case 64:
|
98
|
+
return LLVMInt64Type();
|
99
|
+
case 32:
|
100
|
+
return LLVMInt32Type();
|
101
|
+
case 0:
|
102
|
+
return LLVMVoidType();
|
103
|
+
default:
|
104
|
+
rb_raise(rb_eCompileError, "'%d' is unexpected for llrb_num_to_type", num);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
static void
|
109
|
+
llrb_link_module(LLVMModuleRef mod, const char *funcname)
|
110
|
+
{
|
111
|
+
char *bc_name = ZALLOC_N(char, strlen(LLRB_BITCODE_DIR "/") + strlen(funcname) + strlen(".bc") + 1); // freed in this function
|
112
|
+
strcat(bc_name, LLRB_BITCODE_DIR "/");
|
113
|
+
strcat(bc_name, funcname);
|
114
|
+
strcat(bc_name, ".bc");
|
115
|
+
|
116
|
+
LLVMMemoryBufferRef buf;
|
117
|
+
char *err;
|
118
|
+
if (LLVMCreateMemoryBufferWithContentsOfFile(bc_name, &buf, &err)) {
|
119
|
+
fprintf(stderr, "Failed to load func bitcode: '%s'\n", bc_name);
|
120
|
+
rb_raise(rb_eCompileError, "LLVMCreateMemoryBufferWithContentsOfFile Error: %s", err);
|
121
|
+
}
|
122
|
+
xfree(bc_name);
|
123
|
+
|
124
|
+
LLVMModuleRef func_mod;
|
125
|
+
if (LLVMParseBitcode2(buf, &func_mod)) {
|
126
|
+
rb_raise(rb_eCompileError, "LLVMParseBitcode2 Failed!");
|
127
|
+
}
|
128
|
+
LLVMDisposeMemoryBuffer(buf);
|
129
|
+
|
130
|
+
LLVMLinkModules2(mod, func_mod);
|
131
|
+
}
|
132
|
+
|
133
|
+
static LLVMValueRef
|
134
|
+
llrb_get_function(LLVMModuleRef mod, const char *name)
|
135
|
+
{
|
136
|
+
LLVMValueRef func = LLVMGetNamedFunction(mod, name);
|
137
|
+
if (func) return func;
|
138
|
+
|
139
|
+
for (size_t i = 0; i < llrb_extern_func_num; i++) {
|
140
|
+
if (strcmp(name, llrb_extern_funcs[i].name)) continue;
|
141
|
+
|
142
|
+
if (llrb_extern_funcs[i].has_bc) {
|
143
|
+
llrb_link_module(mod, llrb_extern_funcs[i].name);
|
144
|
+
func = LLVMGetNamedFunction(mod, name);
|
145
|
+
if (func) {
|
146
|
+
return func;
|
147
|
+
} else {
|
148
|
+
rb_raise(rb_eCompileError, "'%s' was not found in bitcode file", name);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
LLVMTypeRef arg_types[LLRB_EXTERN_FUNC_MAX_ARGC];
|
153
|
+
for (unsigned int j = 0; j < llrb_extern_funcs[i].argc; j++) {
|
154
|
+
arg_types[j] = llrb_num_to_type(llrb_extern_funcs[i].argv[j]);
|
155
|
+
}
|
156
|
+
return LLVMAddFunction(mod, llrb_extern_funcs[i].name, LLVMFunctionType(
|
157
|
+
llrb_num_to_type(llrb_extern_funcs[i].return_type), arg_types,
|
158
|
+
llrb_extern_funcs[i].argc, llrb_extern_funcs[i].unlimited));
|
159
|
+
}
|
160
|
+
|
161
|
+
rb_raise(rb_eCompileError, "'%s' is not defined in llrb_extern_funcs", name);
|
162
|
+
}
|
163
|
+
|
164
|
+
#endif // LLRB_COMPILER_FUNCS_H
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/*
|
2
|
+
* compiler/stack.h: Data structure to emulate YARV stack.
|
3
|
+
* This header is used only by compiler.c.
|
4
|
+
*/
|
5
|
+
|
6
|
+
#ifndef LLRB_COMPILER_STACK_H
|
7
|
+
#define LLRB_COMPILER_STACK_H
|
8
|
+
|
9
|
+
// Emulates rb_control_frame's sp (stack pointer), which is function local
|
10
|
+
struct llrb_stack {
|
11
|
+
unsigned int size;
|
12
|
+
unsigned int max;
|
13
|
+
LLVMValueRef *body;
|
14
|
+
};
|
15
|
+
|
16
|
+
static void
|
17
|
+
llrb_stack_push(struct llrb_stack *stack, LLVMValueRef value)
|
18
|
+
{
|
19
|
+
if (stack->size >= stack->max) {
|
20
|
+
rb_raise(rb_eCompileError, "LLRB's internal stack overflow: max=%d, next size=%d", stack->max, stack->size+1);
|
21
|
+
}
|
22
|
+
stack->body[stack->size] = value;
|
23
|
+
stack->size++;
|
24
|
+
}
|
25
|
+
|
26
|
+
static LLVMValueRef
|
27
|
+
llrb_stack_pop(struct llrb_stack *stack)
|
28
|
+
{
|
29
|
+
if (stack->size <= 0) {
|
30
|
+
rb_raise(rb_eCompileError, "LLRB's internal stack underflow: next size=%d", stack->size-1);
|
31
|
+
}
|
32
|
+
stack->size--;
|
33
|
+
return stack->body[stack->size];
|
34
|
+
}
|
35
|
+
|
36
|
+
static inline LLVMValueRef
|
37
|
+
llrb_stack_topn(struct llrb_stack *stack, unsigned int n)
|
38
|
+
{
|
39
|
+
unsigned int last = stack->size - 1;
|
40
|
+
return stack->body[last - n];
|
41
|
+
}
|
42
|
+
|
43
|
+
#endif // LLRB_COMPILER_STACK_H
|
data/ext/llrb/cruby.h
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
/*
|
2
|
+
* cruby.h: Has CRuby's internal data structure definitions including ISeq struct.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef LLRB_CRUBY_H
|
6
|
+
#define LLRB_CRUBY_H
|
7
|
+
|
8
|
+
#ifdef __clang__
|
9
|
+
# pragma clang diagnostic push
|
10
|
+
# pragma clang diagnostic ignored "-Wignored-attributes"
|
11
|
+
# pragma clang diagnostic ignored "-Wunknown-attributes"
|
12
|
+
#endif
|
13
|
+
#include "ruby.h"
|
14
|
+
#ifdef __clang__
|
15
|
+
# pragma clang diagnostic pop
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#pragma GCC diagnostic push
|
19
|
+
#pragma GCC diagnostic ignored "-Wpedantic"
|
20
|
+
#include "cruby/internal.h"
|
21
|
+
#include "cruby/vm_core.h"
|
22
|
+
#pragma GCC diagnostic pop
|
23
|
+
|
24
|
+
#include "cruby/method.h"
|
25
|
+
#include "cruby/vm_exec.h"
|
26
|
+
#include "cruby/iseq.h"
|
27
|
+
|
28
|
+
/* start vm_insnhelper.h (which can't be compiled without calling static function) */
|
29
|
+
|
30
|
+
/* optimize insn */
|
31
|
+
#define FIXNUM_2_P(a, b) ((a) & (b) & 1)
|
32
|
+
#if USE_FLONUM
|
33
|
+
#define FLONUM_2_P(a, b) (((((a)^2) | ((b)^2)) & 3) == 0) /* (FLONUM_P(a) && FLONUM_P(b)) */
|
34
|
+
#else
|
35
|
+
#define FLONUM_2_P(a, b) 0
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#define GET_PREV_EP(ep) ((VALUE *)((ep)[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03))
|
39
|
+
|
40
|
+
/* end vm_insnhelper.h */
|
41
|
+
|
42
|
+
#endif // LLRB_CRUBY_H
|
@@ -0,0 +1,40 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_BUILD_ASSERT_H
|
3
|
+
#define CCAN_BUILD_ASSERT_H
|
4
|
+
|
5
|
+
/**
|
6
|
+
* BUILD_ASSERT - assert a build-time dependency.
|
7
|
+
* @cond: the compile-time condition which must be true.
|
8
|
+
*
|
9
|
+
* Your compile will fail if the condition isn't true, or can't be evaluated
|
10
|
+
* by the compiler. This can only be used within a function.
|
11
|
+
*
|
12
|
+
* Example:
|
13
|
+
* #include <stddef.h>
|
14
|
+
* ...
|
15
|
+
* static char *foo_to_char(struct foo *foo)
|
16
|
+
* {
|
17
|
+
* // This code needs string to be at start of foo.
|
18
|
+
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
|
19
|
+
* return (char *)foo;
|
20
|
+
* }
|
21
|
+
*/
|
22
|
+
#define BUILD_ASSERT(cond) \
|
23
|
+
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
|
24
|
+
|
25
|
+
/**
|
26
|
+
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
|
27
|
+
* @cond: the compile-time condition which must be true.
|
28
|
+
*
|
29
|
+
* Your compile will fail if the condition isn't true, or can't be evaluated
|
30
|
+
* by the compiler. This can be used in an expression: its value is "0".
|
31
|
+
*
|
32
|
+
* Example:
|
33
|
+
* #define foo_to_char(foo) \
|
34
|
+
* ((char *)(foo) \
|
35
|
+
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
|
36
|
+
*/
|
37
|
+
#define BUILD_ASSERT_OR_ZERO(cond) \
|
38
|
+
(sizeof(char [1 - 2*!(cond)]) - 1)
|
39
|
+
|
40
|
+
#endif /* CCAN_BUILD_ASSERT_H */
|
@@ -0,0 +1,63 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_CHECK_TYPE_H
|
3
|
+
#define CCAN_CHECK_TYPE_H
|
4
|
+
|
5
|
+
/**
|
6
|
+
* check_type - issue a warning or build failure if type is not correct.
|
7
|
+
* @expr: the expression whose type we should check (not evaluated).
|
8
|
+
* @type: the exact type we expect the expression to be.
|
9
|
+
*
|
10
|
+
* This macro is usually used within other macros to try to ensure that a macro
|
11
|
+
* argument is of the expected type. No type promotion of the expression is
|
12
|
+
* done: an unsigned int is not the same as an int!
|
13
|
+
*
|
14
|
+
* check_type() always evaluates to 0.
|
15
|
+
*
|
16
|
+
* If your compiler does not support typeof, then the best we can do is fail
|
17
|
+
* to compile if the sizes of the types are unequal (a less complete check).
|
18
|
+
*
|
19
|
+
* Example:
|
20
|
+
* // They should always pass a 64-bit value to _set_some_value!
|
21
|
+
* #define set_some_value(expr) \
|
22
|
+
* _set_some_value((check_type((expr), uint64_t), (expr)))
|
23
|
+
*/
|
24
|
+
|
25
|
+
/**
|
26
|
+
* check_types_match - issue a warning or build failure if types are not same.
|
27
|
+
* @expr1: the first expression (not evaluated).
|
28
|
+
* @expr2: the second expression (not evaluated).
|
29
|
+
*
|
30
|
+
* This macro is usually used within other macros to try to ensure that
|
31
|
+
* arguments are of identical types. No type promotion of the expressions is
|
32
|
+
* done: an unsigned int is not the same as an int!
|
33
|
+
*
|
34
|
+
* check_types_match() always evaluates to 0.
|
35
|
+
*
|
36
|
+
* If your compiler does not support typeof, then the best we can do is fail
|
37
|
+
* to compile if the sizes of the types are unequal (a less complete check).
|
38
|
+
*
|
39
|
+
* Example:
|
40
|
+
* // Do subtraction to get to enclosing type, but make sure that
|
41
|
+
* // pointer is of correct type for that member.
|
42
|
+
* #define container_of(mbr_ptr, encl_type, mbr) \
|
43
|
+
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
|
44
|
+
* ((encl_type *) \
|
45
|
+
* ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr))))
|
46
|
+
*/
|
47
|
+
#if HAVE_TYPEOF
|
48
|
+
#define check_type(expr, type) \
|
49
|
+
((typeof(expr) *)0 != (type *)0)
|
50
|
+
|
51
|
+
#define check_types_match(expr1, expr2) \
|
52
|
+
((typeof(expr1) *)0 != (typeof(expr2) *)0)
|
53
|
+
#else
|
54
|
+
#include "ccan/build_assert/build_assert.h"
|
55
|
+
/* Without typeof, we can only test the sizes. */
|
56
|
+
#define check_type(expr, type) \
|
57
|
+
BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
|
58
|
+
|
59
|
+
#define check_types_match(expr1, expr2) \
|
60
|
+
BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
|
61
|
+
#endif /* HAVE_TYPEOF */
|
62
|
+
|
63
|
+
#endif /* CCAN_CHECK_TYPE_H */
|
@@ -0,0 +1,142 @@
|
|
1
|
+
/* CC0 (Public domain) - see ccan/licenses/CC0 file for details */
|
2
|
+
#ifndef CCAN_CONTAINER_OF_H
|
3
|
+
#define CCAN_CONTAINER_OF_H
|
4
|
+
#include "ccan/check_type/check_type.h"
|
5
|
+
|
6
|
+
/**
|
7
|
+
* container_of - get pointer to enclosing structure
|
8
|
+
* @member_ptr: pointer to the structure member
|
9
|
+
* @containing_type: the type this member is within
|
10
|
+
* @member: the name of this member within the structure.
|
11
|
+
*
|
12
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
13
|
+
* subtraction to return the pointer to the enclosing type.
|
14
|
+
*
|
15
|
+
* Example:
|
16
|
+
* struct foo {
|
17
|
+
* int fielda, fieldb;
|
18
|
+
* // ...
|
19
|
+
* };
|
20
|
+
* struct info {
|
21
|
+
* int some_other_field;
|
22
|
+
* struct foo my_foo;
|
23
|
+
* };
|
24
|
+
*
|
25
|
+
* static struct info *foo_to_info(struct foo *foo)
|
26
|
+
* {
|
27
|
+
* return container_of(foo, struct info, my_foo);
|
28
|
+
* }
|
29
|
+
*/
|
30
|
+
#define container_of(member_ptr, containing_type, member) \
|
31
|
+
((containing_type *) \
|
32
|
+
((char *)(member_ptr) \
|
33
|
+
- container_off(containing_type, member)) \
|
34
|
+
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
35
|
+
|
36
|
+
|
37
|
+
/**
|
38
|
+
* container_of_or_null - get pointer to enclosing structure, or NULL
|
39
|
+
* @member_ptr: pointer to the structure member
|
40
|
+
* @containing_type: the type this member is within
|
41
|
+
* @member: the name of this member within the structure.
|
42
|
+
*
|
43
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
44
|
+
* subtraction to return the pointer to the enclosing type, unless it
|
45
|
+
* is given NULL, in which case it also returns NULL.
|
46
|
+
*
|
47
|
+
* Example:
|
48
|
+
* struct foo {
|
49
|
+
* int fielda, fieldb;
|
50
|
+
* // ...
|
51
|
+
* };
|
52
|
+
* struct info {
|
53
|
+
* int some_other_field;
|
54
|
+
* struct foo my_foo;
|
55
|
+
* };
|
56
|
+
*
|
57
|
+
* static struct info *foo_to_info_allowing_null(struct foo *foo)
|
58
|
+
* {
|
59
|
+
* return container_of_or_null(foo, struct info, my_foo);
|
60
|
+
* }
|
61
|
+
*/
|
62
|
+
static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
63
|
+
{
|
64
|
+
return member_ptr ? (char *)member_ptr - offset : NULL;
|
65
|
+
}
|
66
|
+
#define container_of_or_null(member_ptr, containing_type, member) \
|
67
|
+
((containing_type *) \
|
68
|
+
container_of_or_null_(member_ptr, \
|
69
|
+
container_off(containing_type, member)) \
|
70
|
+
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
71
|
+
|
72
|
+
/**
|
73
|
+
* container_off - get offset to enclosing structure
|
74
|
+
* @containing_type: the type this member is within
|
75
|
+
* @member: the name of this member within the structure.
|
76
|
+
*
|
77
|
+
* Given a pointer to a member of a structure, this macro does
|
78
|
+
* typechecking and figures out the offset to the enclosing type.
|
79
|
+
*
|
80
|
+
* Example:
|
81
|
+
* struct foo {
|
82
|
+
* int fielda, fieldb;
|
83
|
+
* // ...
|
84
|
+
* };
|
85
|
+
* struct info {
|
86
|
+
* int some_other_field;
|
87
|
+
* struct foo my_foo;
|
88
|
+
* };
|
89
|
+
*
|
90
|
+
* static struct info *foo_to_info(struct foo *foo)
|
91
|
+
* {
|
92
|
+
* size_t off = container_off(struct info, my_foo);
|
93
|
+
* return (void *)((char *)foo - off);
|
94
|
+
* }
|
95
|
+
*/
|
96
|
+
#define container_off(containing_type, member) \
|
97
|
+
offsetof(containing_type, member)
|
98
|
+
|
99
|
+
/**
|
100
|
+
* container_of_var - get pointer to enclosing structure using a variable
|
101
|
+
* @member_ptr: pointer to the structure member
|
102
|
+
* @container_var: a pointer of same type as this member's container
|
103
|
+
* @member: the name of this member within the structure.
|
104
|
+
*
|
105
|
+
* Given a pointer to a member of a structure, this macro does pointer
|
106
|
+
* subtraction to return the pointer to the enclosing type.
|
107
|
+
*
|
108
|
+
* Example:
|
109
|
+
* static struct info *foo_to_i(struct foo *foo)
|
110
|
+
* {
|
111
|
+
* struct info *i = container_of_var(foo, i, my_foo);
|
112
|
+
* return i;
|
113
|
+
* }
|
114
|
+
*/
|
115
|
+
#if HAVE_TYPEOF
|
116
|
+
#define container_of_var(member_ptr, container_var, member) \
|
117
|
+
container_of(member_ptr, typeof(*container_var), member)
|
118
|
+
#else
|
119
|
+
#define container_of_var(member_ptr, container_var, member) \
|
120
|
+
((void *)((char *)(member_ptr) - \
|
121
|
+
container_off_var(container_var, member)))
|
122
|
+
#endif
|
123
|
+
|
124
|
+
/**
|
125
|
+
* container_off_var - get offset of a field in enclosing structure
|
126
|
+
* @container_var: a pointer to a container structure
|
127
|
+
* @member: the name of a member within the structure.
|
128
|
+
*
|
129
|
+
* Given (any) pointer to a structure and a its member name, this
|
130
|
+
* macro does pointer subtraction to return offset of member in a
|
131
|
+
* structure memory layout.
|
132
|
+
*
|
133
|
+
*/
|
134
|
+
#if HAVE_TYPEOF
|
135
|
+
#define container_off_var(var, member) \
|
136
|
+
container_off(typeof(*var), member)
|
137
|
+
#else
|
138
|
+
#define container_off_var(var, member) \
|
139
|
+
((const char *)&(var)->member - (const char *)(var))
|
140
|
+
#endif
|
141
|
+
|
142
|
+
#endif /* CCAN_CONTAINER_OF_H */
|