Class: YTLJit::CodeSpace

Inherits:
Object show all
Defined in:
lib/ytljit/marshal.rb,
lib/ytljit/codespace.rb,
ext/ytljit.c

Direct Known Subclasses

ValueSpace

Constant Summary collapse

@@disasm_cache =
{}
@@disasmed_codespace =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCodeSpace

Returns a new instance of CodeSpace.



9
10
11
12
# File 'lib/ytljit/codespace.rb', line 9

def initialize
  @refer_operands = []
  reset
end

Instance Attribute Details

#disasm_cacheObject (readonly)

Returns the value of attribute disasm_cache.



14
15
16
# File 'lib/ytljit/codespace.rb', line 14

def disasm_cache
  @disasm_cache
end

#refer_operandsObject (readonly)

Returns the value of attribute refer_operands.



15
16
17
# File 'lib/ytljit/codespace.rb', line 15

def refer_operands
  @refer_operands
end

Class Method Details

.disasm_cacheObject



5
6
7
# File 'lib/ytljit/codespace.rb', line 5

def self.disasm_cache
  @@disasm_cache
end

Instance Method Details

#[](offset) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'ext/ytljit.c', line 281

VALUE
ytl_code_space_ref(VALUE self, VALUE offset)
{
  struct CodeSpace *raw_cs;

  int raw_offset;
  size_t cooked_offset;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);
  raw_offset = FIX2INT(offset);
  cooked_offset = raw_offset;
  if (raw_offset < 0) {
    size_t rev_offset = -raw_offset;
    cooked_offset = raw_cs->used + rev_offset + 1;
  }

  return INT2FIX(raw_cs->body[cooked_offset]);
}

#[]=(offset, src) ⇒ Object



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'ext/ytljit.c', line 241

VALUE
ytl_code_space_emit(VALUE self, VALUE offset, VALUE src)
{
  struct CodeSpace *raw_cs;
  char *src_ptr;
  size_t src_len;
  int raw_offset;
  size_t cooked_offset;
  struct RData *data_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);
  src_ptr = RSTRING_PTR(src);
  src_len = RSTRING_LEN(src);
  raw_offset = FIX2INT(offset);
  cooked_offset = raw_offset;
  if (raw_offset < 0) {
    cooked_offset = raw_cs->used - raw_offset + 1;
  }

  while (raw_cs->size <= src_len + cooked_offset + 4) {
    size_t newsize = (raw_cs->size + sizeof(struct CodeSpace)) * 2;
    void *new_cs = csalloc(newsize);

    //*(struct CodeSpace *)new_cs = *(struct CodeSpace *)raw_cs;
    //memcpy(new_cs, raw_cs, newsize / 2);
    csfree(raw_cs);
    raw_cs = new_cs;
    raw_cs->size = newsize - sizeof(struct CodeSpace);
  }
  
  memcpy(raw_cs->body + cooked_offset, src_ptr, src_len);
  if (raw_cs->used < cooked_offset + src_len) {
    raw_cs->used = cooked_offset + src_len;
  }
  data_cs = (struct RData *)self;
  data_cs->data = raw_cs;

  return src;
}

#_dump_dataObject



122
123
124
# File 'lib/ytljit/marshal.rb', line 122

def _dump_data
  [@refer_operands, current_pos, code]
end

#_load_data(obj) ⇒ Object



126
127
128
129
130
131
# File 'lib/ytljit/marshal.rb', line 126

def _load_data(obj)
  self[0] = obj.pop
  current_pos = obj.pop
  @org_base_address = base_address
  @refer_operands = obj.pop
end

#base_addressObject



319
320
321
322
323
324
325
326
# File 'ext/ytljit.c', line 319

VALUE
ytl_code_base_address(VALUE self)
{
  struct CodeSpace *raw_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);
  return ULONG2NUM((unsigned long)raw_cs->body);
}

#call(*args) ⇒ Object



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'ext/ytljit.c', line 328

VALUE
ytl_code_call(int argc, VALUE *argv, VALUE self)
{
  VALUE addr;
  VALUE args;
  VALUE rc;
  void *raddr;

  rb_scan_args(argc, argv, "11", &addr, &args);
  raddr = (void *)NUM2ULONG(addr);

#ifdef __x86_64__
  asm("push %%rbx;"
      "push %%rdi;"
      "push %%rsi;"
      "push %%r12;"
      "push %%r13;"
      "push %%r14;"
      "push %%r15;"
      "mov %1, %%rax;"
      "call *%2;"
      "mov %%rax, %0;"
      "pop  %%r15;"
      "pop  %%r14;"
      "pop  %%r13;"
      "pop  %%r12;"
      "pop  %%rsi;"
      "pop  %%rdi;"
      "pop  %%rbx;"
      : "=r"(rc) 
      : "r"(args), "r"(raddr) 
      : "%rax", "%rbx");
#elif  __CYGWIN__
  asm("mov %1, %%eax;"
      "call *%2;"
      "mov %%eax, %0;"
      : "=r"(rc) 
      : "r"(args), "r"(raddr) 
      : "%eax", "%ebx");
#elif  __i386__
  /* push %ebx ? */
  asm("mov %1, %%eax;"
      "call *%2;"
      "mov %%eax, %0;"
      : "=r"(rc) 
      : "r"(args), "r"(raddr) 
      : "%eax");
  /* pop %ebx ? */
#else
#error "only i386 or x86-64 is supported"
#endif

  return rc;
}

#codeObject



383
384
385
386
387
388
389
390
391
# File 'ext/ytljit.c', line 383

VALUE
ytl_code_space_code(VALUE self)
{
  struct CodeSpace *raw_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);

  return rb_str_new(raw_cs->body, raw_cs->used);
}

#current_posObject



300
301
302
303
304
305
306
307
# File 'ext/ytljit.c', line 300

VALUE
ytl_code_current_pos(VALUE self)
{
  struct CodeSpace *raw_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);
  return INT2NUM(raw_cs->used);
}

#current_pos=(val) ⇒ Object



309
310
311
312
313
314
315
316
317
# File 'ext/ytljit.c', line 309

VALUE
ytl_code_set_current_pos(VALUE self, VALUE val)
{
  struct CodeSpace *raw_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);
  raw_cs->used = NUM2INT(val);
  return val;
}

#disassembleObject



90
91
92
93
94
95
# File 'lib/ytljit/codespace.rb', line 90

def disassemble
  fill_disasm_cache
  @@disasm_cache.each do |add, asm|
    print "#{add}:  #{asm}\n"
  end
end

#emit(code) ⇒ Object



22
23
24
# File 'lib/ytljit/codespace.rb', line 22

def emit(code)
  self[self.current_pos] = code
end

#fill_disasm_cacheObject



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ytljit/codespace.rb', line 52

def fill_disasm_cache
  if @@disasmed_codespace[self] then
    return
  end
  @@disasmed_codespace[self] = true
  tmpfp = Tempfile.open("ytljitcode")
  tmpfp.write code
  tmpfp.close(false)
  # quick dirty hack to work on Cygwin & Mac OS X/Core2Duo
  # TODO: bdf and instruction set architecture should be automatically selected
  case $ruby_platform
  when /x86_64-darwin/
    objcopy_cmd = "gobjcopy -I binary -O mach-o-i386 -B i386 --adjust-vma=#{base_address} #{tmpfp.path}"
    objdump_cmd = "gobjdump -M x86-64 -D #{tmpfp.path}"

  when /x86_64/
    objcopy_cmd = "objcopy -I binary -O elf64-x86-64 -B i386 --adjust-vma=#{base_address} #{tmpfp.path}"
    objdump_cmd = "objdump -M x86-64 -D #{tmpfp.path}"

  when /i.86/
    objcopy_cmd = "objcopy -I binary -O elf32-i386 -B i386 --adjust-vma=#{base_address} #{tmpfp.path}"
    objdump_cmd = "objdump -M i386 -D #{tmpfp.path}"
  end
  system(objcopy_cmd)
  File.popen(objdump_cmd, "r") {|fp|
    fp.readlines.each do |lin|
      if /([0-9a-f]*):(\t[0-9a-f ]+? *\t.*)/ =~ lin then
        src = $2
        addr = $1
        $symbol_table.each do |val, sym|
          src.gsub!(val.to_s(16), "#{sym} (#{val})")
        end
        @@disasm_cache[addr] = src
      end
    end
  }
end

#resetObject



17
18
19
20
# File 'lib/ytljit/codespace.rb', line 17

def reset
  @org_base_address = base_address
  self.current_pos = 0
end

#to_sObject



393
394
395
396
397
398
399
400
401
# File 'ext/ytljit.c', line 393

VALUE
ytl_code_space_to_s(VALUE self)
{
  struct CodeSpace *raw_cs;

  raw_cs = (struct CodeSpace *)DATA_PTR(self);

  return rb_sprintf("#<codeSpace %p base=%p:...>", (void *)self, (void *)raw_cs->body);
}

#update_referObject



44
45
46
47
48
49
50
# File 'lib/ytljit/codespace.rb', line 44

def update_refer
  @refer_operands.each do |refop|
    refop.refer.each do |stfn|
      stfn.call
    end
  end
end

#var_base_address(offset = 0) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/ytljit/codespace.rb', line 26

def var_base_address(offset = 0)
  func = lambda {
    base_address + offset
  }
  ovi32 = OpVarMemAddress.new(func)
  @refer_operands.push ovi32
  ovi32
end

#var_base_immidiate_address(offset = 0) ⇒ Object



35
36
37
38
39
40
41
42
# File 'lib/ytljit/codespace.rb', line 35

def var_base_immidiate_address(offset = 0)
  func = lambda {
    base_address + offset
  }
  ovi32 = OpVarImmidiateAddress.new(func)
  @refer_operands.push ovi32
  ovi32
end