llrb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.gitmodules +4 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +56 -0
  8. data/README.md +311 -0
  9. data/Rakefile +30 -0
  10. data/bin/bm_app_fib +41 -0
  11. data/bin/bm_empty_method +33 -0
  12. data/bin/bm_loop_while +27 -0
  13. data/bin/bm_plus +33 -0
  14. data/bin/console +14 -0
  15. data/bin/loop_while.rb +5 -0
  16. data/bin/setup +8 -0
  17. data/ext/llrb/cfg.h +124 -0
  18. data/ext/llrb/compiler.c +987 -0
  19. data/ext/llrb/compiler/funcs.h +164 -0
  20. data/ext/llrb/compiler/stack.h +43 -0
  21. data/ext/llrb/cruby.h +42 -0
  22. data/ext/llrb/cruby/ccan/build_assert/build_assert.h +40 -0
  23. data/ext/llrb/cruby/ccan/check_type/check_type.h +63 -0
  24. data/ext/llrb/cruby/ccan/container_of/container_of.h +142 -0
  25. data/ext/llrb/cruby/ccan/list/list.h +773 -0
  26. data/ext/llrb/cruby/ccan/str/str.h +16 -0
  27. data/ext/llrb/cruby/internal.h +1774 -0
  28. data/ext/llrb/cruby/iseq.h +252 -0
  29. data/ext/llrb/cruby/method.h +213 -0
  30. data/ext/llrb/cruby/node.h +520 -0
  31. data/ext/llrb/cruby/probes_helper.h +43 -0
  32. data/ext/llrb/cruby/ruby_assert.h +54 -0
  33. data/ext/llrb/cruby/ruby_atomic.h +233 -0
  34. data/ext/llrb/cruby/thread_pthread.h +54 -0
  35. data/ext/llrb/cruby/vm_core.h +1646 -0
  36. data/ext/llrb/cruby/vm_debug.h +37 -0
  37. data/ext/llrb/cruby/vm_exec.h +182 -0
  38. data/ext/llrb/cruby/vm_opts.h +57 -0
  39. data/ext/llrb/cruby_extra/id.h +220 -0
  40. data/ext/llrb/cruby_extra/insns.inc +113 -0
  41. data/ext/llrb/cruby_extra/insns_info.inc +796 -0
  42. data/ext/llrb/cruby_extra/probes.h +80 -0
  43. data/ext/llrb/extconf.rb +102 -0
  44. data/ext/llrb/llrb.c +148 -0
  45. data/ext/llrb/optimizer.cc +118 -0
  46. data/ext/llrb/parser.c +191 -0
  47. data/ext/llrb/profiler.c +336 -0
  48. data/ext/llrb_insn_checkkeyword.c +20 -0
  49. data/ext/llrb_insn_checkmatch.c +28 -0
  50. data/ext/llrb_insn_concatarray.c +23 -0
  51. data/ext/llrb_insn_concatstrings.c +21 -0
  52. data/ext/llrb_insn_defined.c +9 -0
  53. data/ext/llrb_insn_getclassvariable.c +10 -0
  54. data/ext/llrb_insn_getinstancevariable.c +44 -0
  55. data/ext/llrb_insn_getlocal.c +14 -0
  56. data/ext/llrb_insn_getlocal_level0.c +8 -0
  57. data/ext/llrb_insn_getlocal_level1.c +8 -0
  58. data/ext/llrb_insn_getspecial.c +14 -0
  59. data/ext/llrb_insn_invokeblock.c +39 -0
  60. data/ext/llrb_insn_invokesuper.c +47 -0
  61. data/ext/llrb_insn_opt_aref.c +25 -0
  62. data/ext/llrb_insn_opt_aset.c +28 -0
  63. data/ext/llrb_insn_opt_div.c +32 -0
  64. data/ext/llrb_insn_opt_eq.c +57 -0
  65. data/ext/llrb_insn_opt_ge.c +28 -0
  66. data/ext/llrb_insn_opt_gt.c +38 -0
  67. data/ext/llrb_insn_opt_le.c +29 -0
  68. data/ext/llrb_insn_opt_lt.c +38 -0
  69. data/ext/llrb_insn_opt_ltlt.c +27 -0
  70. data/ext/llrb_insn_opt_minus.c +36 -0
  71. data/ext/llrb_insn_opt_mod.c +32 -0
  72. data/ext/llrb_insn_opt_mult.c +30 -0
  73. data/ext/llrb_insn_opt_neq.c +103 -0
  74. data/ext/llrb_insn_opt_plus.c +48 -0
  75. data/ext/llrb_insn_opt_send_without_block.c +45 -0
  76. data/ext/llrb_insn_opt_str_freeze.c +12 -0
  77. data/ext/llrb_insn_putspecialobject.c +23 -0
  78. data/ext/llrb_insn_send.c +49 -0
  79. data/ext/llrb_insn_setclassvariable.c +19 -0
  80. data/ext/llrb_insn_setconstant.c +23 -0
  81. data/ext/llrb_insn_setinstancevariable.c +48 -0
  82. data/ext/llrb_insn_setlocal.c +16 -0
  83. data/ext/llrb_insn_setlocal_level0.c +9 -0
  84. data/ext/llrb_insn_setlocal_level1.c +10 -0
  85. data/ext/llrb_insn_setspecial.c +15 -0
  86. data/ext/llrb_insn_splatarray.c +13 -0
  87. data/ext/llrb_insn_throw.c +11 -0
  88. data/ext/llrb_insn_trace.c +37 -0
  89. data/ext/llrb_push_result.c +14 -0
  90. data/ext/llrb_self_from_cfp.c +12 -0
  91. data/ext/llrb_set_pc.c +8 -0
  92. data/lib/llrb.rb +2 -0
  93. data/lib/llrb/jit.rb +76 -0
  94. data/lib/llrb/start.rb +2 -0
  95. data/lib/llrb/version.rb +3 -0
  96. data/llrb.gemspec +48 -0
  97. data/wercker.yml +31 -0
  98. 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
@@ -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 */