-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathsplat.rb
75 lines (59 loc) · 2.05 KB
/
splat.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Compiler
def handle_splat(scope,args)
# FIXME: Quick and dirty splat handling:
# - If the last node has a splat, we cheat and assume it's
# from the arguments rather than a proper Ruby Array.
# - We assume we can just allocate args.length+1+numargs
# - We wastefully do it in two rounds and muck directly
# with %esp for now until I figure out how to do this
# more cleanly.
splat = args.last.is_a?(Array) && args.last.first == :splat
numargs = nil
if !splat
return yield(args,false)
end
# FIXME: This is just a disaster waiting to happen
# (needs proper register allocation)
@e.comment("*#{args.last.last.to_s}")
reg = compile_eval_arg(scope,:numargs)
# "reg" is set to numargs - (number of non-splat arguments to the *method we're in*)
m = scope.method
@e.subl(m.args.size-1,reg)
@e.sall(2,reg)
@e.subl(reg,@e.sp)
@e.with_register do |argend|
@e.movl(reg,argend)
reg = compile_eval_arg(scope,args.last.last)
@e.addl(reg,argend)
@e.with_register do |dest|
@e.movl(@e.sp,dest)
lc = @e.get_local
@e.jmp(lc) # So we can handle the zero argument case
ls = @e.local
@e.load_indirect(reg,@e.scratch)
@e.save_indirect(@e.scratch,dest)
@e.addl(4,@e.result)
@e.addl(4,dest)
@e.local(lc) # So we can jump straight to condition
@e.cmpl(reg,argend)
@e.jne(ls)
# At this point, dest points to the position *after* the
# splat arguments. Subtracting the stack pointer, and shifting
# right twice gives us the number of splat arguments
@e.subl(@e.sp,dest)
@e.sarl(2,dest)
@e.movl(dest,@e.scratch)
@e.comment("*#{args.last.last.to_s} end")
args.pop
end
end
yield(args, true)
@e.pushl(@e.result)
reg = compile_eval_arg(scope,:numargs)
@e.subl(args.size+1,reg)
@e.sall(2,reg)
@e.movl(reg,@e.scratch)
@e.popl(@e.result)
@e.addl(@e.scratch,@e.sp)
end
end