cast_off 0.2.0
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.
- data/README +578 -0
- data/README.en +256 -0
- data/bin/CastOff +145 -0
- data/cast_off.gemspec +25 -0
- data/ext/cast_off/cast_off.c.rb +1386 -0
- data/ext/cast_off/cast_off.h +24 -0
- data/ext/cast_off/depend +70 -0
- data/ext/cast_off/extconf.rb +19 -0
- data/ext/cast_off/generated_c_include/inline_api.h +507 -0
- data/ext/cast_off/generated_c_include/iter_api.h +595 -0
- data/ext/cast_off/generated_c_include/unbox_api.h.rb +76 -0
- data/ext/cast_off/generated_c_include/vm_api.h +751 -0
- data/ext/cast_off/ruby_source/atomic.h +56 -0
- data/ext/cast_off/ruby_source/constant.h +34 -0
- data/ext/cast_off/ruby_source/debug.h +41 -0
- data/ext/cast_off/ruby_source/eval_intern.h +234 -0
- data/ext/cast_off/ruby_source/gc.h +98 -0
- data/ext/cast_off/ruby_source/id.h +175 -0
- data/ext/cast_off/ruby_source/insns.inc +179 -0
- data/ext/cast_off/ruby_source/insns_info.inc +695 -0
- data/ext/cast_off/ruby_source/internal.h +227 -0
- data/ext/cast_off/ruby_source/iseq.h +125 -0
- data/ext/cast_off/ruby_source/manual_update.h +135 -0
- data/ext/cast_off/ruby_source/method.h +105 -0
- data/ext/cast_off/ruby_source/node.h +503 -0
- data/ext/cast_off/ruby_source/thread_pthread.h +51 -0
- data/ext/cast_off/ruby_source/thread_win32.h +40 -0
- data/ext/cast_off/ruby_source/vm_core.h +756 -0
- data/ext/cast_off/ruby_source/vm_exec.h +184 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.c +1748 -0
- data/ext/cast_off/ruby_source/vm_insnhelper.h +220 -0
- data/ext/cast_off/ruby_source/vm_opts.h +51 -0
- data/lib/cast_off.rb +15 -0
- data/lib/cast_off/compile.rb +629 -0
- data/lib/cast_off/compile/basicblock.rb +144 -0
- data/lib/cast_off/compile/cfg.rb +391 -0
- data/lib/cast_off/compile/code_manager.rb +284 -0
- data/lib/cast_off/compile/configuration.rb +2368 -0
- data/lib/cast_off/compile/dependency.rb +240 -0
- data/lib/cast_off/compile/information.rb +775 -0
- data/lib/cast_off/compile/instruction.rb +446 -0
- data/lib/cast_off/compile/ir/call_ir.rb +2348 -0
- data/lib/cast_off/compile/ir/guard_ir.rb +423 -0
- data/lib/cast_off/compile/ir/jump_ir.rb +223 -0
- data/lib/cast_off/compile/ir/operand.rb +934 -0
- data/lib/cast_off/compile/ir/param_ir.rb +98 -0
- data/lib/cast_off/compile/ir/return_ir.rb +92 -0
- data/lib/cast_off/compile/ir/simple_ir.rb +808 -0
- data/lib/cast_off/compile/ir/sub_ir.rb +212 -0
- data/lib/cast_off/compile/iseq.rb +454 -0
- data/lib/cast_off/compile/method_information.rb +1384 -0
- data/lib/cast_off/compile/namespace/namespace.rb +556 -0
- data/lib/cast_off/compile/namespace/uuid.rb +323 -0
- data/lib/cast_off/compile/stack.rb +65 -0
- data/lib/cast_off/compile/translator.rb +1562 -0
- data/lib/cast_off/suggestion.rb +98 -0
- data/lib/cast_off/util.rb +58 -0
- metadata +107 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
/**********************************************************************
|
2
|
+
|
3
|
+
insnhelper.h - helper macros to implement each instructions
|
4
|
+
|
5
|
+
$Author$
|
6
|
+
created at: 04/01/01 15:50:34 JST
|
7
|
+
|
8
|
+
Copyright (C) 2004-2007 Koichi Sasada
|
9
|
+
|
10
|
+
**********************************************************************/
|
11
|
+
|
12
|
+
#ifndef RUBY_INSNHELPER_H
|
13
|
+
#define RUBY_INSNHELPER_H
|
14
|
+
|
15
|
+
/**
|
16
|
+
* VM Debug Level
|
17
|
+
*
|
18
|
+
* debug level:
|
19
|
+
* 0: no debug output
|
20
|
+
* 1: show instruction name
|
21
|
+
* 2: show stack frame when control stack frame is changed
|
22
|
+
* 3: show stack status
|
23
|
+
* 4: show register
|
24
|
+
* 5:
|
25
|
+
* 10: gc check
|
26
|
+
*/
|
27
|
+
|
28
|
+
#ifndef VMDEBUG
|
29
|
+
#define VMDEBUG 0
|
30
|
+
#endif
|
31
|
+
|
32
|
+
#if 0
|
33
|
+
#undef VMDEBUG
|
34
|
+
#define VMDEBUG 3
|
35
|
+
#endif
|
36
|
+
|
37
|
+
enum {
|
38
|
+
BOP_PLUS,
|
39
|
+
BOP_MINUS,
|
40
|
+
BOP_MULT,
|
41
|
+
BOP_DIV,
|
42
|
+
BOP_MOD,
|
43
|
+
BOP_EQ,
|
44
|
+
BOP_EQQ,
|
45
|
+
BOP_LT,
|
46
|
+
BOP_LE,
|
47
|
+
BOP_LTLT,
|
48
|
+
BOP_AREF,
|
49
|
+
BOP_ASET,
|
50
|
+
BOP_LENGTH,
|
51
|
+
BOP_SIZE,
|
52
|
+
BOP_SUCC,
|
53
|
+
BOP_GT,
|
54
|
+
BOP_GE,
|
55
|
+
BOP_NOT,
|
56
|
+
BOP_NEQ,
|
57
|
+
|
58
|
+
BOP_LAST_
|
59
|
+
};
|
60
|
+
|
61
|
+
extern char ruby_vm_redefined_flag[BOP_LAST_];
|
62
|
+
extern VALUE ruby_vm_const_missing_count;
|
63
|
+
|
64
|
+
|
65
|
+
/**********************************************************/
|
66
|
+
/* deal with stack */
|
67
|
+
/**********************************************************/
|
68
|
+
|
69
|
+
#define PUSH(x) (SET_SV(x), INC_SP(1))
|
70
|
+
#define TOPN(n) (*(GET_SP()-(n)-1))
|
71
|
+
#define POPN(n) (DEC_SP(n))
|
72
|
+
#define POP() (DEC_SP(1))
|
73
|
+
#define STACK_ADDR_FROM_TOP(n) (GET_SP()-(n))
|
74
|
+
|
75
|
+
#define GET_TOS() (tos) /* dummy */
|
76
|
+
|
77
|
+
/**********************************************************/
|
78
|
+
/* deal with registers */
|
79
|
+
/**********************************************************/
|
80
|
+
|
81
|
+
#define REG_CFP (reg_cfp)
|
82
|
+
#define REG_PC (REG_CFP->pc)
|
83
|
+
#define REG_SP (REG_CFP->sp)
|
84
|
+
#define REG_LFP (REG_CFP->lfp)
|
85
|
+
#define REG_DFP (REG_CFP->dfp)
|
86
|
+
|
87
|
+
#define RESTORE_REGS() do { \
|
88
|
+
REG_CFP = th->cfp; \
|
89
|
+
} while (0)
|
90
|
+
|
91
|
+
#define REG_A reg_a
|
92
|
+
#define REG_B reg_b
|
93
|
+
|
94
|
+
#ifdef COLLECT_USAGE_ANALYSIS
|
95
|
+
#define USAGE_ANALYSIS_REGISTER_HELPER(a, b, v) \
|
96
|
+
(USAGE_ANALYSIS_REGISTER((a), (b)), (v))
|
97
|
+
#else
|
98
|
+
#define USAGE_ANALYSIS_REGISTER_HELPER(a, b, v) (v)
|
99
|
+
#endif
|
100
|
+
|
101
|
+
/* PC */
|
102
|
+
#define GET_PC() (USAGE_ANALYSIS_REGISTER_HELPER(0, 0, REG_PC))
|
103
|
+
#define SET_PC(x) (REG_PC = (USAGE_ANALYSIS_REGISTER_HELPER(0, 1, (x))))
|
104
|
+
#define GET_CURRENT_INSN() (*GET_PC())
|
105
|
+
#define GET_OPERAND(n) (GET_PC()[(n)])
|
106
|
+
#define ADD_PC(n) (SET_PC(REG_PC + (n)))
|
107
|
+
|
108
|
+
#define GET_PC_COUNT() (REG_PC - GET_ISEQ()->iseq_encoded)
|
109
|
+
#define JUMP(dst) (REG_PC += (dst))
|
110
|
+
|
111
|
+
/* FP */
|
112
|
+
#define GET_CFP() (USAGE_ANALYSIS_REGISTER_HELPER(2, 0, REG_CFP))
|
113
|
+
#define GET_LFP() (USAGE_ANALYSIS_REGISTER_HELPER(3, 0, REG_LFP))
|
114
|
+
#define SET_LFP(x) (REG_LFP = (USAGE_ANALYSIS_REGISTER_HELPER(3, 1, (x))))
|
115
|
+
#define GET_DFP() (USAGE_ANALYSIS_REGISTER_HELPER(4, 0, REG_DFP))
|
116
|
+
#define SET_DFP(x) (REG_DFP = (USAGE_ANALYSIS_REGISTER_HELPER(4, 1, (x))))
|
117
|
+
|
118
|
+
/* SP */
|
119
|
+
#define GET_SP() (USAGE_ANALYSIS_REGISTER_HELPER(1, 0, REG_SP))
|
120
|
+
#define SET_SP(x) (REG_SP = (USAGE_ANALYSIS_REGISTER_HELPER(1, 1, (x))))
|
121
|
+
#define INC_SP(x) (REG_SP += (USAGE_ANALYSIS_REGISTER_HELPER(1, 1, (x))))
|
122
|
+
#define DEC_SP(x) (REG_SP -= (USAGE_ANALYSIS_REGISTER_HELPER(1, 1, (x))))
|
123
|
+
#define SET_SV(x) (*GET_SP() = (x))
|
124
|
+
/* set current stack value as x */
|
125
|
+
|
126
|
+
#define GET_SP_COUNT() (REG_SP - th->stack)
|
127
|
+
|
128
|
+
/* instruction sequence C struct */
|
129
|
+
#define GET_ISEQ() (GET_CFP()->iseq)
|
130
|
+
|
131
|
+
/**********************************************************/
|
132
|
+
/* deal with variables */
|
133
|
+
/**********************************************************/
|
134
|
+
|
135
|
+
#define GET_PREV_DFP(dfp) ((VALUE *)((dfp)[0] & ~0x03))
|
136
|
+
|
137
|
+
#define GET_GLOBAL(entry) rb_gvar_get((struct rb_global_entry*)(entry))
|
138
|
+
#define SET_GLOBAL(entry, val) rb_gvar_set((struct rb_global_entry*)(entry), (val))
|
139
|
+
|
140
|
+
#define GET_CONST_INLINE_CACHE(dst) ((IC) * (GET_PC() + (dst) + 2))
|
141
|
+
|
142
|
+
/**********************************************************/
|
143
|
+
/* deal with values */
|
144
|
+
/**********************************************************/
|
145
|
+
|
146
|
+
#define GET_SELF() (USAGE_ANALYSIS_REGISTER_HELPER(5, 0, GET_CFP()->self))
|
147
|
+
|
148
|
+
/**********************************************************/
|
149
|
+
/* deal with control flow 2: method/iterator */
|
150
|
+
/**********************************************************/
|
151
|
+
|
152
|
+
#define COPY_CREF(c1, c2) do { \
|
153
|
+
NODE *__tmp_c2 = (c2); \
|
154
|
+
(c1)->nd_clss = __tmp_c2->nd_clss; \
|
155
|
+
(c1)->nd_visi = __tmp_c2->nd_visi;\
|
156
|
+
(c1)->nd_next = __tmp_c2->nd_next; \
|
157
|
+
if (__tmp_c2->flags & NODE_FL_CREF_PUSHED_BY_EVAL) { \
|
158
|
+
(c1)->flags |= NODE_FL_CREF_PUSHED_BY_EVAL; \
|
159
|
+
} \
|
160
|
+
} while (0)
|
161
|
+
|
162
|
+
#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \
|
163
|
+
VALUE v = vm_call_method(th, GET_CFP(), (num), (blockptr), (flag), (id), (me), (recv)); \
|
164
|
+
if (v == Qundef) { \
|
165
|
+
RESTORE_REGS(); \
|
166
|
+
NEXT_INSN(); \
|
167
|
+
} \
|
168
|
+
else { \
|
169
|
+
val = v; \
|
170
|
+
} \
|
171
|
+
} while (0)
|
172
|
+
|
173
|
+
#define GET_BLOCK_PTR() \
|
174
|
+
((rb_block_t *)(GC_GUARDED_PTR_REF(GET_LFP()[0] & \
|
175
|
+
((GET_LFP()[0] & 0x02) - 0x02))))
|
176
|
+
|
177
|
+
/**********************************************************/
|
178
|
+
/* deal with control flow 3: exception */
|
179
|
+
/**********************************************************/
|
180
|
+
|
181
|
+
|
182
|
+
/**********************************************************/
|
183
|
+
/* others */
|
184
|
+
/**********************************************************/
|
185
|
+
|
186
|
+
/* optimize insn */
|
187
|
+
#define FIXNUM_2_P(a, b) ((a) & (b) & 1)
|
188
|
+
#define BASIC_OP_UNREDEFINED_P(op) (LIKELY(ruby_vm_redefined_flag[(op)] == 0))
|
189
|
+
#define HEAP_CLASS_OF(obj) RBASIC(obj)->klass
|
190
|
+
|
191
|
+
#ifndef USE_IC_FOR_SPECIALIZED_METHOD
|
192
|
+
#define USE_IC_FOR_SPECIALIZED_METHOD 1
|
193
|
+
#endif
|
194
|
+
|
195
|
+
#if USE_IC_FOR_SPECIALIZED_METHOD
|
196
|
+
|
197
|
+
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
198
|
+
VALUE klass = CLASS_OF(recv); \
|
199
|
+
CALL_METHOD((num), 0, 0, (id), vm_method_search((id), klass, ic), (recv)); \
|
200
|
+
} while (0)
|
201
|
+
|
202
|
+
#else
|
203
|
+
|
204
|
+
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
205
|
+
VALUE klass = CLASS_OF(recv); \
|
206
|
+
CALL_METHOD((num), 0, 0, (id), rb_method_entry(klass, (id)), (recv)); \
|
207
|
+
} while (0)
|
208
|
+
|
209
|
+
#endif
|
210
|
+
|
211
|
+
static VALUE ruby_vm_global_state_version = 1;
|
212
|
+
|
213
|
+
#define GET_VM_STATE_VERSION() (ruby_vm_global_state_version)
|
214
|
+
#define INC_VM_STATE_VERSION() do { \
|
215
|
+
ruby_vm_global_state_version = (ruby_vm_global_state_version + 1); \
|
216
|
+
if (ruby_vm_global_state_version == 0) vm_clear_all_cache(); \
|
217
|
+
} while (0)
|
218
|
+
static void vm_clear_all_cache(void);
|
219
|
+
|
220
|
+
#endif /* RUBY_INSNHELPER_H */
|
@@ -0,0 +1,51 @@
|
|
1
|
+
/*-*-c-*-*/
|
2
|
+
/**********************************************************************
|
3
|
+
|
4
|
+
vm_opts.h - VM optimize option
|
5
|
+
|
6
|
+
$Author$
|
7
|
+
|
8
|
+
Copyright (C) 2004-2007 Koichi Sasada
|
9
|
+
|
10
|
+
**********************************************************************/
|
11
|
+
|
12
|
+
|
13
|
+
#ifndef RUBY_VM_OPTS_H
|
14
|
+
#define RUBY_VM_OPTS_H
|
15
|
+
|
16
|
+
/* Compile options.
|
17
|
+
* You can change these options at runtime by VM::CompileOption.
|
18
|
+
* Following definitions are default values.
|
19
|
+
*/
|
20
|
+
|
21
|
+
#define OPT_TRACE_INSTRUCTION 1
|
22
|
+
#define OPT_TAILCALL_OPTIMIZATION 0
|
23
|
+
#define OPT_PEEPHOLE_OPTIMIZATION 1
|
24
|
+
#define OPT_SPECIALISED_INSTRUCTION 1
|
25
|
+
#define OPT_INLINE_CONST_CACHE 1
|
26
|
+
|
27
|
+
|
28
|
+
/* Build Options.
|
29
|
+
* You can't change these options at runtime.
|
30
|
+
*/
|
31
|
+
|
32
|
+
/* C compiler depend */
|
33
|
+
#define OPT_DIRECT_THREADED_CODE 1
|
34
|
+
#define OPT_TOKEN_THREADED_CODE 0
|
35
|
+
#define OPT_CALL_THREADED_CODE 0
|
36
|
+
|
37
|
+
/* VM running option */
|
38
|
+
#define OPT_CHECKED_RUN 1
|
39
|
+
#define OPT_INLINE_METHOD_CACHE 1
|
40
|
+
#define OPT_BLOCKINLINING 0
|
41
|
+
|
42
|
+
/* architecture independent, affects generated code */
|
43
|
+
#define OPT_OPERANDS_UNIFICATION 0
|
44
|
+
#define OPT_INSTRUCTIONS_UNIFICATION 0
|
45
|
+
#define OPT_UNIFY_ALL_COMBINATION 0
|
46
|
+
#define OPT_STACK_CACHING 0
|
47
|
+
|
48
|
+
/* misc */
|
49
|
+
#define SUPPORT_JOKE 0
|
50
|
+
|
51
|
+
#endif /* RUBY_VM_OPTS_H */
|
data/lib/cast_off.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cast_off.so'
|
2
|
+
require 'cast_off/util'
|
3
|
+
require 'cast_off/suggestion'
|
4
|
+
require 'cast_off/compile/dependency'
|
5
|
+
require 'cast_off/compile/method_information'
|
6
|
+
require 'cast_off/compile/configuration'
|
7
|
+
require 'cast_off/compile/code_manager'
|
8
|
+
require 'cast_off/compile'
|
9
|
+
|
10
|
+
module CastOff
|
11
|
+
extend CastOff::Util
|
12
|
+
extend CastOff::Compiler
|
13
|
+
end
|
14
|
+
CastOff.clear_settings()
|
15
|
+
|
@@ -0,0 +1,629 @@
|
|
1
|
+
# coding=utf-8
|
2
|
+
|
3
|
+
module CastOff
|
4
|
+
module Compiler
|
5
|
+
include CastOff::Util
|
6
|
+
|
7
|
+
DefaultSuggestionIO = Object.new
|
8
|
+
DefaultSuggestionIO.extend(CastOff::Util)
|
9
|
+
def DefaultSuggestionIO.puts(*msg)
|
10
|
+
vlog(msg)
|
11
|
+
end
|
12
|
+
@@suggestion_io = DefaultSuggestionIO
|
13
|
+
def set_suggestion_io(io)
|
14
|
+
@@suggestion_io = io
|
15
|
+
end
|
16
|
+
|
17
|
+
def verbose(b)
|
18
|
+
CastOff::Util.set_verbose_mode(b)
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear()
|
22
|
+
CodeManager.clear()
|
23
|
+
end
|
24
|
+
|
25
|
+
@@blacklist = [
|
26
|
+
]
|
27
|
+
|
28
|
+
@@autoload_proc = nil
|
29
|
+
def autoload()
|
30
|
+
return false if autocompile_running?
|
31
|
+
if autoload_running?
|
32
|
+
@@autoload_proc.call()
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
return true if load()
|
36
|
+
|
37
|
+
compiled = nil
|
38
|
+
@@autoload_proc = lambda {
|
39
|
+
compiled = CodeManager.load_autocompiled() unless compiled
|
40
|
+
return false unless compiled
|
41
|
+
fin = __load(compiled)
|
42
|
+
hook_class_definition_end(nil) if fin
|
43
|
+
fin
|
44
|
+
}
|
45
|
+
hook_class_definition_end(@@autoload_proc)
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def load(force = false)
|
50
|
+
return @@autoload_proc.call() if autoload_running? && !force
|
51
|
+
compiled = CodeManager.load_autocompiled()
|
52
|
+
return false unless compiled
|
53
|
+
__load(compiled)
|
54
|
+
end
|
55
|
+
|
56
|
+
@@compilation_threshold = 100
|
57
|
+
def compilation_threshold=(num)
|
58
|
+
raise(ArgumentError.new("first argument should be Integer")) unless num.is_a?(Integer)
|
59
|
+
raise(ArgumentError.new("threshold should be more than 0")) unless num >= 0
|
60
|
+
@@compilation_threshold = num
|
61
|
+
end
|
62
|
+
|
63
|
+
@@autocompile_proc = nil
|
64
|
+
@@compile_auto_incremental = true
|
65
|
+
def autocompile()
|
66
|
+
return false if autoload_running?
|
67
|
+
return true if autocompile_running?
|
68
|
+
class_table = {}
|
69
|
+
bind_table = {}
|
70
|
+
location_table = {}
|
71
|
+
cinfo_table = {}
|
72
|
+
compiled = []
|
73
|
+
@@autocompile_proc = lambda {|event, file, line, mid, bind, klass, cinfo|
|
74
|
+
return unless file
|
75
|
+
return if line < 0
|
76
|
+
return if event != 'call'
|
77
|
+
return if file =~ /\(/
|
78
|
+
|
79
|
+
# TODO should handle singleton class
|
80
|
+
|
81
|
+
# trace method invocation count
|
82
|
+
method_table = class_table[klass]
|
83
|
+
unless method_table
|
84
|
+
method_table = Hash.new(0)
|
85
|
+
class_table[klass] = method_table
|
86
|
+
end
|
87
|
+
count = (method_table[mid] += 1)
|
88
|
+
if count == 1
|
89
|
+
bind_table[[klass, mid]] = bind
|
90
|
+
location_table[[klass, mid]] = [File.expand_path(file), line]
|
91
|
+
end
|
92
|
+
if cinfo
|
93
|
+
table = (cinfo_table[[klass, mid]] ||= {})
|
94
|
+
table[cinfo] = true
|
95
|
+
end
|
96
|
+
if count == @@compilation_threshold && @@compile_auto_incremental
|
97
|
+
compiled << __autocompile(klass, mid, bind_table, location_table, compiled.size)
|
98
|
+
end
|
99
|
+
}
|
100
|
+
hook_method_invocation(@@autocompile_proc)
|
101
|
+
at_exit do
|
102
|
+
hook_method_invocation(nil) # clear trace
|
103
|
+
unless @@compile_auto_incremental
|
104
|
+
targets = []
|
105
|
+
class_table.each do |klass, method_table|
|
106
|
+
method_table.each do |mid, count|
|
107
|
+
next unless count >= @@compilation_threshold
|
108
|
+
targets << [klass, mid, count]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
targets = sort_targets(targets, cinfo_table)
|
112
|
+
targets.each_with_index do |(klass, mid, count), index|
|
113
|
+
dlog("#{count}: #{klass} #{mid}")
|
114
|
+
compiled << __autocompile(klass, mid, bind_table, location_table, index)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
compiled.compact!
|
118
|
+
CodeManager.dump_auto_compiled(compiled)
|
119
|
+
end
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
123
|
+
def compile_instance_methods(klass, bind = nil, skip = [])
|
124
|
+
raise ArgumentError.new("first argument should be Class") unless klass.instance_of?(Class)
|
125
|
+
raise ArgumentError.new("second argument should be Binding") unless !bind || bind.instance_of?(Binding)
|
126
|
+
logger = self
|
127
|
+
klass.class_eval do
|
128
|
+
instance_methods(false).each_with_index do |mid, idx|
|
129
|
+
next if skip.include?(mid)
|
130
|
+
args = [klass, mid, bind]
|
131
|
+
begin
|
132
|
+
CastOff.compile(*args.compact())
|
133
|
+
logger.vlog("#{idx}: compile #{mid}")
|
134
|
+
rescue UnsupportedError => e
|
135
|
+
logger.vlog("#{idx}: failed to compile #{self}##{mid} (#{e.message})")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@@original_instance_method_iseq = {}
|
142
|
+
def delete_original_instance_method_iseq(target, mid)
|
143
|
+
t = override_target(target, mid)
|
144
|
+
@@original_instance_method_iseq.delete([t, mid])
|
145
|
+
end
|
146
|
+
|
147
|
+
def compile(target, mid, bind_or_typemap = nil, typemap = nil)
|
148
|
+
case target
|
149
|
+
when Class, Module
|
150
|
+
# ok
|
151
|
+
else
|
152
|
+
raise(ArgumentError.new("first argument should be Class or Module"))
|
153
|
+
end
|
154
|
+
mid, bind, typemap = parse_arguments(mid, bind_or_typemap, typemap)
|
155
|
+
t = override_target(target, mid)
|
156
|
+
iseq = @@original_instance_method_iseq[[t, mid]] || get_iseq(target, mid, false)
|
157
|
+
manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind)
|
158
|
+
manager.compilation_target_is_a(t, mid, false)
|
159
|
+
set_direct_call(target, mid, target.instance_of?(Class) ? :class : :module, manager, configuration)
|
160
|
+
load_binary(manager, configuration, suggestion, iseq, bind)
|
161
|
+
t = override_target(target, mid)
|
162
|
+
dlog("override target of #{target}##{mid} is #{t}")
|
163
|
+
__send__("register_method_#{manager.signiture}", t)
|
164
|
+
@@original_instance_method_iseq[[t, mid]] = iseq
|
165
|
+
@@manager_table[manager.signiture] = manager
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
@@original_singleton_method_iseq = {}
|
170
|
+
def delete_original_singleton_method_iseq(obj, mid)
|
171
|
+
@@original_singleton_method_iseq.delete([obj, mid])
|
172
|
+
end
|
173
|
+
|
174
|
+
def compile_singleton_method(obj, mid, bind_or_typemap = nil, typemap = nil)
|
175
|
+
mid, bind, typemap = parse_arguments(mid, bind_or_typemap, typemap)
|
176
|
+
iseq = @@original_singleton_method_iseq[[obj, mid]] || get_iseq(obj, mid, true)
|
177
|
+
manager, configuration, suggestion = compile_iseq(iseq, mid, typemap, false, bind)
|
178
|
+
manager.compilation_target_is_a(obj, mid, true)
|
179
|
+
set_direct_call(obj, mid, :singleton, manager, configuration)
|
180
|
+
load_binary(manager, configuration, suggestion, iseq, bind)
|
181
|
+
__send__("register_singleton_method_#{manager.signiture}", obj)
|
182
|
+
@@original_singleton_method_iseq[[obj, mid]] = iseq
|
183
|
+
@@manager_table[manager.signiture] = manager
|
184
|
+
true
|
185
|
+
end
|
186
|
+
|
187
|
+
@@loaded_binary = {}
|
188
|
+
def execute(typemap = nil, &block)
|
189
|
+
raise(ArgumentError.new('no block given')) unless block
|
190
|
+
iseq = get_iseq_from_block(block)
|
191
|
+
key = iseq.__id__
|
192
|
+
if !@@loaded_binary[key]
|
193
|
+
bind = block.binding
|
194
|
+
manager, configuration, suggestion = compile_iseq(iseq, nil, typemap, false, bind)
|
195
|
+
load_binary(manager, configuration, suggestion, iseq, bind)
|
196
|
+
@@loaded_binary[key] = manager.signiture
|
197
|
+
end
|
198
|
+
sign = @@loaded_binary[key]
|
199
|
+
recv = get_caller()
|
200
|
+
__send__(sign, recv)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def execute_no_hook()
|
206
|
+
bug() unless block_given?
|
207
|
+
begin
|
208
|
+
hook_m = hook_method_invocation(nil)
|
209
|
+
hook_c = hook_class_definition_end(nil)
|
210
|
+
yield
|
211
|
+
ensure
|
212
|
+
if hook_m
|
213
|
+
bug() unless autocompile_running?
|
214
|
+
hook_method_invocation(@@autocompile_proc)
|
215
|
+
end
|
216
|
+
if hook_c
|
217
|
+
bug() unless autoload_running?
|
218
|
+
hook_class_definition_end(@@autoload_proc)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def compile_iseq(iseq, mid, typemap, is_proc, bind)
|
224
|
+
filepath, line_no = *iseq.to_a.slice(7, 2)
|
225
|
+
raise(UnsupportedError.new(<<-EOS)) unless filepath && File.exist?(filepath)
|
226
|
+
|
227
|
+
Currently, CastOff cannot compile method which source file is not exist.
|
228
|
+
#{filepath.nil? ? 'nil' : filepath} is not exist.
|
229
|
+
EOS
|
230
|
+
manager = CodeManager.new(filepath, line_no)
|
231
|
+
suggestion = Suggestion.new(iseq, @@suggestion_io)
|
232
|
+
configuration = nil
|
233
|
+
manager.do_atomically() do
|
234
|
+
execute_no_hook() do
|
235
|
+
configuration = __compile(iseq, manager, typemap || {}, mid, is_proc, bind, suggestion)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
bug() unless configuration.instance_of?(Configuration)
|
239
|
+
[manager, configuration, suggestion]
|
240
|
+
end
|
241
|
+
|
242
|
+
def parse_arguments(mid, bind_or_typemap, typemap)
|
243
|
+
case mid
|
244
|
+
when Symbol
|
245
|
+
# nothing to do
|
246
|
+
when String
|
247
|
+
mid = mid.intern
|
248
|
+
else
|
249
|
+
raise(ArgumentError.new('method name should be Symbol or String'))
|
250
|
+
end
|
251
|
+
case bind_or_typemap
|
252
|
+
when Binding
|
253
|
+
bind = bind_or_typemap
|
254
|
+
when Hash
|
255
|
+
raise(ArgumentError.new("Invalid arugments")) if typemap
|
256
|
+
bind = nil
|
257
|
+
typemap = bind_or_typemap
|
258
|
+
when NilClass
|
259
|
+
# nothing to do
|
260
|
+
bind = nil
|
261
|
+
else
|
262
|
+
raise(ArgumentError.new("third argument should be Binding or Hash"))
|
263
|
+
end
|
264
|
+
[mid, bind, typemap]
|
265
|
+
end
|
266
|
+
|
267
|
+
def union_base_configuration(conf, manager)
|
268
|
+
if CastOff.use_base_configuration?
|
269
|
+
u = manager.load_base_configuration()
|
270
|
+
unless u
|
271
|
+
bind = conf.bind
|
272
|
+
u = Configuration.new({}, bind ? bind.bind : nil)
|
273
|
+
manager.save_base_configuration(u)
|
274
|
+
end
|
275
|
+
conf.union(u)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
@@manager_table = {}
|
280
|
+
def re_compile(signiture, sampling_table)
|
281
|
+
manager = @@manager_table[signiture]
|
282
|
+
return false unless manager
|
283
|
+
bug() unless manager.instance_of?(CodeManager)
|
284
|
+
reciever_result, return_value_result = parse_sampling_table(sampling_table)
|
285
|
+
update_p = update_base_configuration(manager, reciever_result, return_value_result)
|
286
|
+
compilation_target = manager.compilation_target
|
287
|
+
bug() unless compilation_target
|
288
|
+
target = compilation_target.target_object
|
289
|
+
mid = compilation_target.method_id
|
290
|
+
singleton = compilation_target.singleton_method?
|
291
|
+
vlog("re-compile(#{target}#{singleton ? '.' : '#'}#{mid}): update_p = #{update_p}, reciever_result = #{reciever_result}, return_value_result = #{return_value_result}")
|
292
|
+
return false unless update_p
|
293
|
+
ann = manager.load_annotation() || {}
|
294
|
+
bug() unless ann.instance_of?(Hash)
|
295
|
+
manager.version_up()
|
296
|
+
begin
|
297
|
+
__send__(singleton ? 'compile_singleton_method' : 'compile', target, mid, ann)
|
298
|
+
rescue => e
|
299
|
+
vlog("re-compilation failed: #{target}#{singleton ? '.' : '#'}#{mid}")
|
300
|
+
end
|
301
|
+
true
|
302
|
+
end
|
303
|
+
|
304
|
+
class ReCompilation < StandardError; end
|
305
|
+
|
306
|
+
def __compile(iseq, manager, annotation, mid, is_proc, bind, suggestion)
|
307
|
+
if reuse_compiled_binary? && !manager.target_file_updated?
|
308
|
+
# already compiled
|
309
|
+
if CastOff.development? || !CastOff.skip_configuration_check? || manager.last_configuration_enabled_development?
|
310
|
+
conf = Configuration.new(annotation, bind)
|
311
|
+
union_base_configuration(conf, manager)
|
312
|
+
last_conf = manager.load_last_configuration()
|
313
|
+
if last_conf && conf == last_conf
|
314
|
+
dlog("reuse compiled binary")
|
315
|
+
return last_conf
|
316
|
+
end
|
317
|
+
else
|
318
|
+
dlog("reuse compiled binary")
|
319
|
+
last_conf = manager.load_last_configuration()
|
320
|
+
if last_conf
|
321
|
+
return last_conf
|
322
|
+
end
|
323
|
+
conf = Configuration.new(annotation, bind)
|
324
|
+
union_base_configuration(conf, manager)
|
325
|
+
end
|
326
|
+
else
|
327
|
+
conf = Configuration.new(annotation, bind)
|
328
|
+
union_base_configuration(conf, manager)
|
329
|
+
end
|
330
|
+
vlog("use configuration #{conf}")
|
331
|
+
|
332
|
+
require 'cast_off/compile/namespace/uuid'
|
333
|
+
require 'cast_off/compile/namespace/namespace'
|
334
|
+
require 'cast_off/compile/instruction'
|
335
|
+
require 'cast_off/compile/iseq'
|
336
|
+
require 'cast_off/compile/ir/simple_ir'
|
337
|
+
require 'cast_off/compile/ir/operand'
|
338
|
+
require 'cast_off/compile/ir/sub_ir'
|
339
|
+
require 'cast_off/compile/ir/jump_ir'
|
340
|
+
require 'cast_off/compile/ir/param_ir'
|
341
|
+
require 'cast_off/compile/ir/call_ir'
|
342
|
+
require 'cast_off/compile/ir/return_ir'
|
343
|
+
require 'cast_off/compile/ir/guard_ir'
|
344
|
+
require 'cast_off/compile/translator'
|
345
|
+
require 'cast_off/compile/cfg'
|
346
|
+
require 'cast_off/compile/basicblock'
|
347
|
+
require 'cast_off/compile/stack'
|
348
|
+
require 'cast_off/compile/information'
|
349
|
+
conf.validate()
|
350
|
+
bug() unless conf
|
351
|
+
dep = Dependency.new()
|
352
|
+
block_inlining = true
|
353
|
+
while true
|
354
|
+
begin
|
355
|
+
translator = Translator.new(iseq, conf, mid, is_proc, block_inlining, suggestion, dep, manager)
|
356
|
+
c_source = translator.to_c()
|
357
|
+
break
|
358
|
+
rescue ReCompilation
|
359
|
+
bug() unless block_inlining
|
360
|
+
block_inlining = false # FIXME get re-compilation type from exception object
|
361
|
+
dlog("failed to inline block...")
|
362
|
+
end
|
363
|
+
end
|
364
|
+
conf.use_method_frame(!block_inlining)
|
365
|
+
bug() unless c_source
|
366
|
+
translator.suggest()
|
367
|
+
manager.compile_c_source(c_source, conf, dep)
|
368
|
+
manager.save_annotation(annotation)
|
369
|
+
manager.dump_development_mark(conf)
|
370
|
+
conf
|
371
|
+
end
|
372
|
+
|
373
|
+
def __load(compiled)
|
374
|
+
begin
|
375
|
+
compiled.dup.each do |entry|
|
376
|
+
klass, mid, singleton, file, line, bind = entry
|
377
|
+
if @@blacklist.include?(mid)
|
378
|
+
compiled.delete(entry)
|
379
|
+
next
|
380
|
+
end
|
381
|
+
bind = bind.bind if bind
|
382
|
+
entry.pop # release BindingWrapper
|
383
|
+
if singleton
|
384
|
+
iseq = @@original_singleton_method_iseq[[klass, mid]] || get_iseq(klass, mid, true)
|
385
|
+
else
|
386
|
+
t = override_target(klass, mid)
|
387
|
+
iseq = @@original_instance_method_iseq[[t, mid]] || get_iseq(klass, mid, false)
|
388
|
+
end
|
389
|
+
f, l = *iseq.to_a.slice(7, 2)
|
390
|
+
if f == file && l == line
|
391
|
+
begin
|
392
|
+
if singleton
|
393
|
+
CastOff.compile_singleton_method(klass, mid, bind)
|
394
|
+
else
|
395
|
+
CastOff.compile(klass, mid, bind)
|
396
|
+
end
|
397
|
+
vlog("load #{klass}##{mid}")
|
398
|
+
rescue UnsupportedError
|
399
|
+
vlog("unsupported #{klass}##{mid}")
|
400
|
+
end
|
401
|
+
else
|
402
|
+
dlog("iseq.filepath = #{f}, file = #{file}\niseq.line = #{l}, line = #{line}")
|
403
|
+
end
|
404
|
+
compiled.delete(entry)
|
405
|
+
end
|
406
|
+
if compiled.empty?
|
407
|
+
vlog("---------- load finish ----------")
|
408
|
+
true
|
409
|
+
else
|
410
|
+
false
|
411
|
+
end
|
412
|
+
rescue => e
|
413
|
+
vlog("catch exception #{e.class}: #{e}\n#{e.backtrace.join("\n")}")
|
414
|
+
false
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def autocompile_running?
|
419
|
+
!!@@autocompile_proc
|
420
|
+
end
|
421
|
+
|
422
|
+
def autoload_running?
|
423
|
+
!!@@autoload_proc
|
424
|
+
end
|
425
|
+
|
426
|
+
def __autocompile(klass, mid, bind_table, location_table, index)
|
427
|
+
return nil unless klass.instance_of?(Class) || klass.instance_of?(Module) # FIXME
|
428
|
+
return nil if klass.name =~ /CastOff/ # ここで弾いておかないと、__compile の require で __load が走る。
|
429
|
+
# Namespace のほうはあらかじめ require しておくことで回避。
|
430
|
+
# Namespace 以外は CastOff を含むので問題無し。
|
431
|
+
if klass.instance_methods(false).include?(mid) || klass.private_instance_methods(false).include?(mid)
|
432
|
+
singleton = false
|
433
|
+
else
|
434
|
+
return nil unless klass.singleton_methods(false).include?(mid)
|
435
|
+
singleton = true
|
436
|
+
end
|
437
|
+
begin
|
438
|
+
bind = bind_table[[klass, mid]]
|
439
|
+
if singleton
|
440
|
+
CastOff.compile_singleton_method(klass, mid, bind)
|
441
|
+
else
|
442
|
+
CastOff.compile(klass, mid, bind)
|
443
|
+
end
|
444
|
+
location = location_table[[klass, mid]]
|
445
|
+
begin
|
446
|
+
Marshal.dump(klass)
|
447
|
+
rescue TypeError => e
|
448
|
+
vlog("failed to marshal dump #{klass}: #{e.message}")
|
449
|
+
return nil
|
450
|
+
end
|
451
|
+
vlog("#{index}: compile #{klass}#{singleton ? '.' : '#'}#{mid}")
|
452
|
+
[klass, mid, singleton] + location + [Configuration::BindingWrapper.new(bind)] # klass, mid, file, line, binding
|
453
|
+
rescue UnsupportedError => e
|
454
|
+
vlog("#{index}: failed to compile #{klass}#{singleton ? '.' : '#'}#{mid} (#{e.message})")
|
455
|
+
nil
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
def __sort_targets(entry, targets, cinfo_table)
|
460
|
+
result = []
|
461
|
+
unless cinfo_table[entry]
|
462
|
+
result << entry
|
463
|
+
dlog("<< #{entry}: nil")
|
464
|
+
return result # FIXME
|
465
|
+
end
|
466
|
+
|
467
|
+
targets.each do |te|
|
468
|
+
bug() if entry == te
|
469
|
+
next unless cinfo_table[te]
|
470
|
+
next unless cinfo_table[te].keys.include?(entry) # entry calls te
|
471
|
+
next if cinfo_table[entry].keys.include?(te) # cycle
|
472
|
+
targets.delete(te)
|
473
|
+
result += __sort_targets(te, targets, cinfo_table)
|
474
|
+
end
|
475
|
+
dlog("<< #{entry}: #{cinfo_table[entry].keys}")
|
476
|
+
result << entry
|
477
|
+
result
|
478
|
+
end
|
479
|
+
|
480
|
+
def sort_targets(targets, cinfo_table)
|
481
|
+
result = []
|
482
|
+
counts = {}
|
483
|
+
targets = targets.sort{|v0, v1| v1.last <=> v0.last}
|
484
|
+
targets.each{|klass, mid, count| counts[[klass, mid]] = count}
|
485
|
+
targets = targets.map{|klass, mid, count| [klass, mid]}
|
486
|
+
until targets.empty?
|
487
|
+
entry = targets.shift
|
488
|
+
result += __sort_targets(entry, targets, cinfo_table)
|
489
|
+
end
|
490
|
+
result.map!{|entry| entry + [counts[entry]]}
|
491
|
+
bug() unless result.size == counts.size
|
492
|
+
result
|
493
|
+
end
|
494
|
+
|
495
|
+
def parse_sampling_table(sampling_table)
|
496
|
+
reciever_result = {}
|
497
|
+
return_value_result = {}
|
498
|
+
sampling_table.each do |(key0, val0)|
|
499
|
+
case key0
|
500
|
+
when Symbol
|
501
|
+
bug() unless val0.is_a?(Hash)
|
502
|
+
reciever_result[key0] = val0.keys
|
503
|
+
when Class
|
504
|
+
bug() unless val0.is_a?(Hash)
|
505
|
+
newval = {}
|
506
|
+
val0.each do |(key1, val1)|
|
507
|
+
bug() unless key1.is_a?(Symbol)
|
508
|
+
bug() unless val1.is_a?(Hash)
|
509
|
+
newval[key1] = val1.keys
|
510
|
+
end
|
511
|
+
return_value_result[key0] = newval
|
512
|
+
else
|
513
|
+
bug("#{key0}, #{key0.class}")
|
514
|
+
end
|
515
|
+
end
|
516
|
+
bug() unless (reciever_result.keys & return_value_result.keys).empty?
|
517
|
+
[reciever_result, return_value_result]
|
518
|
+
end
|
519
|
+
|
520
|
+
def update_configuration(configuration, reciever_result, return_value_result)
|
521
|
+
update_p = false
|
522
|
+
update_p |= configuration.update_variable_configuration(reciever_result)
|
523
|
+
update_p |= configuration.update_return_value_configuration(return_value_result)
|
524
|
+
update_p
|
525
|
+
end
|
526
|
+
|
527
|
+
def update_base_configuration(manager, reciever_result, return_value_result)
|
528
|
+
base_configuration = manager.load_base_configuration()
|
529
|
+
unless base_configuration
|
530
|
+
last = manager.load_last_configuration()
|
531
|
+
bind = last ? (last.bind ? last.bind.bind : nil) : nil
|
532
|
+
base_configuration = Configuration.new({}, bind)
|
533
|
+
end
|
534
|
+
bug() unless base_configuration.instance_of?(Configuration)
|
535
|
+
update_p = update_configuration(base_configuration, reciever_result, return_value_result)
|
536
|
+
return false unless update_p
|
537
|
+
manager.save_base_configuration(base_configuration)
|
538
|
+
true
|
539
|
+
end
|
540
|
+
|
541
|
+
def set_sampling_table(suggestion, manager, configuration)
|
542
|
+
if CastOff.development?
|
543
|
+
h = Hash.new()
|
544
|
+
__send__("register_sampling_table_#{manager.signiture}", h)
|
545
|
+
suggestion.add_handler do
|
546
|
+
reciever_result, return_value_result = parse_sampling_table(h)
|
547
|
+
update_base_configuration(manager, reciever_result, return_value_result)
|
548
|
+
if reciever_result.size > 0
|
549
|
+
msg = "These are unresolved local variables sampling results."
|
550
|
+
ary = []
|
551
|
+
reciever_result.each do |key0, val0|
|
552
|
+
bug() unless key0.is_a?(Symbol)
|
553
|
+
bug() unless val0.is_a?(Array)
|
554
|
+
val0.each do |t|
|
555
|
+
ary << [key0.to_s, t.to_s]
|
556
|
+
end
|
557
|
+
end
|
558
|
+
suggestion.add_suggestion(msg, ["<Variable>", "<SamplingResultClass>"], ary)
|
559
|
+
end
|
560
|
+
if return_value_result.size > 0
|
561
|
+
msg = "These are unresolved method return values sampling results."
|
562
|
+
ary = []
|
563
|
+
return_value_result.each do |key0, val0|
|
564
|
+
bug() unless key0.is_a?(Class)
|
565
|
+
bug() unless val0.is_a?(Hash)
|
566
|
+
val0.each do |(mid, types)|
|
567
|
+
types.each{|t| ary << ["#{key0}##{mid}", t.to_s]}
|
568
|
+
end
|
569
|
+
end
|
570
|
+
suggestion.add_suggestion(msg, ["<Method>", "<SamplingResultClass>"], ary)
|
571
|
+
end
|
572
|
+
|
573
|
+
bug() unless configuration
|
574
|
+
s0 = configuration.to_s
|
575
|
+
update_p = update_configuration(configuration, reciever_result, return_value_result)
|
576
|
+
s1 = configuration.to_s
|
577
|
+
configuration.compact()
|
578
|
+
s2 = configuration.to_s
|
579
|
+
if update_p
|
580
|
+
bug() if s0 == s1
|
581
|
+
else
|
582
|
+
bug() if s0 != s1
|
583
|
+
end
|
584
|
+
if update_p
|
585
|
+
suggestion.add_suggestion("You specify following type map to CastOff", ["Your Annotation"], [[s0]], false)
|
586
|
+
suggestion.add_suggestion("CastOff suggests you to use following type map", ["CastOff Suggestion"], [[s2]], false)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
def set_direct_call(obj, mid, type, manager, configuration)
|
593
|
+
bug() unless configuration
|
594
|
+
return if configuration.use_method_frame?
|
595
|
+
CastOff.should_be_call_directly(obj, mid, type)
|
596
|
+
end
|
597
|
+
|
598
|
+
def hook_method_override(manager, configuration, function_pointer_initializer)
|
599
|
+
bug() unless configuration
|
600
|
+
return unless configuration.alert_override?
|
601
|
+
dep = manager.load_dependency()
|
602
|
+
dep.check(configuration)
|
603
|
+
dep.hook(function_pointer_initializer)
|
604
|
+
end
|
605
|
+
|
606
|
+
def load_binary(manager, configuration, suggestion, iseq, bind)
|
607
|
+
execute_no_hook() do
|
608
|
+
so = manager.compiled_binary
|
609
|
+
sign = manager.signiture
|
610
|
+
bug("#{so} is not exist") unless File.exist?(so)
|
611
|
+
load_compiled_file(so)
|
612
|
+
function_pointer_initializer = "initialize_fptr_#{sign}".intern
|
613
|
+
hook_method_override(manager, configuration, function_pointer_initializer)
|
614
|
+
__send__("register_iseq_#{sign}", iseq)
|
615
|
+
__send__("register_ifunc_#{sign}")
|
616
|
+
set_sampling_table(suggestion, manager, configuration)
|
617
|
+
suggestion.dump_at_exit()
|
618
|
+
__send__(function_pointer_initializer)
|
619
|
+
__send__("prefetch_constants_#{sign}", bind) if bind
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
def capture_instruction()
|
624
|
+
a = [] # setlocal
|
625
|
+
a[0] = a # getlocal, setn, pop, leave
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|