fastruby 0.0.3 → 0.0.4
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/CHANGELOG +21 -0
- data/README +1 -2
- data/Rakefile +2 -2
- data/TODO +0 -2
- data/lib/fastruby/builder.rb +19 -1
- data/lib/fastruby/custom_require.rb +48 -0
- data/lib/fastruby/object.rb +73 -10
- data/lib/fastruby/translator.rb +637 -131
- data/lib/fastruby.rb +4 -0
- data/spec/base_spec.rb +37 -0
- data/spec/block/break_spec.rb +190 -0
- data/spec/block/next_spec.rb +85 -0
- data/spec/exception_spec.rb +440 -0
- data/spec/module_spec.rb +36 -0
- data/spec/return_spec.rb +99 -0
- data/spec/singleton_spec.rb +76 -0
- data/spec/sugar_spec.rb +2 -2
- data/spec/variable_spec.rb +64 -0
- metadata +12 -4
    
        data/lib/fastruby/translator.rb
    CHANGED
    
    | @@ -26,6 +26,14 @@ require "fastruby/method_extension" | |
| 26 26 | 
             
            module FastRuby
         | 
| 27 27 | 
             
              class Context
         | 
| 28 28 |  | 
| 29 | 
            +
                class UnwindFastrubyFrame < Exception
         | 
| 30 | 
            +
                  def initialize(ex,target_frame,return_value)
         | 
| 31 | 
            +
                    @ex = ex
         | 
| 32 | 
            +
                    @target_frame = target_frame
         | 
| 33 | 
            +
                    @return_value = return_value
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 29 37 | 
             
                attr_accessor :infer_lvar_map
         | 
| 30 38 | 
             
                attr_accessor :alt_method_name
         | 
| 31 39 | 
             
                attr_accessor :locals
         | 
| @@ -34,32 +42,48 @@ module FastRuby | |
| 34 42 | 
             
                attr_reader :extra_code
         | 
| 35 43 | 
             
                attr_reader :yield_signature
         | 
| 36 44 |  | 
| 37 | 
            -
                def initialize
         | 
| 45 | 
            +
                def initialize(common_func = true)
         | 
| 38 46 | 
             
                  @infer_lvar_map = Hash.new
         | 
| 39 47 | 
             
                  @extra_code = ""
         | 
| 40 48 | 
             
                  @options = {}
         | 
| 49 | 
            +
                  @frame_struct = "struct {
         | 
| 50 | 
            +
                    void* parent_frame;
         | 
| 51 | 
            +
                    void* target_frame;
         | 
| 52 | 
            +
                    void* plocals;
         | 
| 53 | 
            +
                    jmp_buf jmp;
         | 
| 54 | 
            +
                    VALUE return_value;
         | 
| 55 | 
            +
                    VALUE exception;
         | 
| 56 | 
            +
                    int rescue;
         | 
| 57 | 
            +
                    VALUE last_error;
         | 
| 58 | 
            +
                  }"
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  @block_struct = "struct {
         | 
| 61 | 
            +
                    void* block_function_address;
         | 
| 62 | 
            +
                    void* block_function_param;
         | 
| 63 | 
            +
                  }"
         | 
| 41 64 |  | 
| 42 65 | 
             
                  extra_code << '#include "node.h"
         | 
| 43 66 | 
             
                  '
         | 
| 44 67 |  | 
| 45 | 
            -
                   | 
| 46 | 
            -
                     | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
                  extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
         | 
| 52 | 
            -
                    rb_ivar_set(recv,idvar,value);
         | 
| 53 | 
            -
                    return value;
         | 
| 54 | 
            -
                  }
         | 
| 55 | 
            -
                  "
         | 
| 68 | 
            +
                  if common_func
         | 
| 69 | 
            +
                    extra_code << "static VALUE _rb_gvar_set(void* ge,VALUE value) {
         | 
| 70 | 
            +
                      rb_gvar_set((struct global_entry*)ge,value);
         | 
| 71 | 
            +
                      return value;
         | 
| 72 | 
            +
                    }
         | 
| 73 | 
            +
                    "
         | 
| 56 74 |  | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 75 | 
            +
                    extra_code << "static VALUE _rb_ivar_set(VALUE recv,ID idvar, VALUE value) {
         | 
| 76 | 
            +
                      rb_ivar_set(recv,idvar,value);
         | 
| 77 | 
            +
                      return value;
         | 
| 78 | 
            +
                    }
         | 
| 79 | 
            +
                    "
         | 
| 62 80 |  | 
| 81 | 
            +
                    extra_code << "static VALUE _lvar_assing(VALUE* destination,VALUE value) {
         | 
| 82 | 
            +
                      *destination = value;
         | 
| 83 | 
            +
                      return value;
         | 
| 84 | 
            +
                    }
         | 
| 85 | 
            +
                    "
         | 
| 86 | 
            +
                  end
         | 
| 63 87 | 
             
                end
         | 
| 64 88 |  | 
| 65 89 | 
             
                def on_block
         | 
| @@ -71,10 +95,10 @@ module FastRuby | |
| 71 95 | 
             
                  send("to_c_" + tree[0].to_s, tree);
         | 
| 72 96 | 
             
                end
         | 
| 73 97 |  | 
| 74 | 
            -
                def anonymous_function | 
| 98 | 
            +
                def anonymous_function
         | 
| 75 99 |  | 
| 76 100 | 
             
                  name = "anonymous" + rand(10000000).to_s
         | 
| 77 | 
            -
                  extra_code <<  | 
| 101 | 
            +
                  extra_code << yield(name)
         | 
| 78 102 |  | 
| 79 103 | 
             
                  name
         | 
| 80 104 | 
             
                end
         | 
| @@ -105,9 +129,6 @@ module FastRuby | |
| 105 129 |  | 
| 106 130 | 
             
                  caller_code = nil
         | 
| 107 131 |  | 
| 108 | 
            -
                  str_lvar_initialization = @locals_struct + " *plocals;
         | 
| 109 | 
            -
                                            plocals = (void*)param;"
         | 
| 110 | 
            -
             | 
| 111 132 | 
             
                  recvtype = infer_type(recv_tree || s(:self))
         | 
| 112 133 |  | 
| 113 134 | 
             
                  address = nil
         | 
| @@ -179,14 +200,19 @@ module FastRuby | |
| 179 200 |  | 
| 180 201 | 
             
                  anonymous_impl = tree[3]
         | 
| 181 202 |  | 
| 182 | 
            -
                  str_lvar_initialization = @ | 
| 183 | 
            -
             | 
| 203 | 
            +
                  str_lvar_initialization = "#{@frame_struct} *pframe;
         | 
| 204 | 
            +
                                             #{@locals_struct} *plocals;
         | 
| 205 | 
            +
                                            pframe = (void*)param;
         | 
| 206 | 
            +
                                            plocals = (void*)pframe->plocals;
         | 
| 207 | 
            +
                                            "
         | 
| 184 208 |  | 
| 185 209 | 
             
                  str_arg_initialization = ""
         | 
| 186 210 |  | 
| 187 211 | 
             
                  str_impl = ""
         | 
| 188 212 |  | 
| 189 213 | 
             
                  with_extra_inference(extra_inference) do
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                    on_block do
         | 
| 190 216 | 
             
                      # if impl_tree is a block, implement the last node with a return
         | 
| 191 217 | 
             
                      if anonymous_impl
         | 
| 192 218 | 
             
                        if anonymous_impl[0] == :block
         | 
| @@ -209,7 +235,7 @@ module FastRuby | |
| 209 235 | 
             
                      else
         | 
| 210 236 | 
             
                        str_impl = "last_expression = Qnil;"
         | 
| 211 237 | 
             
                      end
         | 
| 212 | 
            -
             | 
| 238 | 
            +
                    end
         | 
| 213 239 | 
             
                  end
         | 
| 214 240 |  | 
| 215 241 | 
             
                  if convention == :ruby or convention == :cruby
         | 
| @@ -260,11 +286,44 @@ module FastRuby | |
| 260 286 | 
             
                    str_arg_initialization
         | 
| 261 287 |  | 
| 262 288 | 
             
                    block_code = proc { |name| "
         | 
| 263 | 
            -
                      static VALUE #{name}(VALUE arg, VALUE  | 
| 289 | 
            +
                      static VALUE #{name}(VALUE arg, VALUE _parent_frame) {
         | 
| 264 290 | 
             
                        // block for call to #{call_tree[2]}
         | 
| 265 291 | 
             
                        VALUE last_expression = Qnil;
         | 
| 266 292 |  | 
| 267 | 
            -
                        #{ | 
| 293 | 
            +
                        #{@frame_struct} frame;
         | 
| 294 | 
            +
                        #{@frame_struct} *pframe = (void*)&frame;
         | 
| 295 | 
            +
                        #{@frame_struct} *parent_frame = (void*)_parent_frame;
         | 
| 296 | 
            +
                        #{@locals_struct} *plocals;
         | 
| 297 | 
            +
             | 
| 298 | 
            +
                        frame.plocals = parent_frame->plocals;
         | 
| 299 | 
            +
                        frame.parent_frame = parent_frame;
         | 
| 300 | 
            +
                        frame.return_value = Qnil;
         | 
| 301 | 
            +
                        frame.target_frame = &frame;
         | 
| 302 | 
            +
                        frame.exception = Qnil;
         | 
| 303 | 
            +
                        frame.rescue = 0;
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                        plocals = frame.plocals;
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                        if (setjmp(frame.jmp) != 0) {
         | 
| 308 | 
            +
                          if (pframe->target_frame != pframe) {
         | 
| 309 | 
            +
                            if (pframe->target_frame == (void*)-3) {
         | 
| 310 | 
            +
                               return pframe->return_value;
         | 
| 311 | 
            +
                            }
         | 
| 312 | 
            +
             | 
| 313 | 
            +
                            VALUE ex = rb_funcall(
         | 
| 314 | 
            +
                                    (VALUE)#{UnwindFastrubyFrame.internal_value},
         | 
| 315 | 
            +
                                    #{:new.to_i},
         | 
| 316 | 
            +
                                    3,
         | 
| 317 | 
            +
                                    pframe->exception,
         | 
| 318 | 
            +
                                    LONG2FIX(pframe->target_frame),
         | 
| 319 | 
            +
                                    pframe->return_value
         | 
| 320 | 
            +
                                    );
         | 
| 321 | 
            +
                            rb_funcall(plocals->self, #{:raise.to_i}, 1, ex);
         | 
| 322 | 
            +
                          }
         | 
| 323 | 
            +
                          return frame.return_value;
         | 
| 324 | 
            +
                        }
         | 
| 325 | 
            +
             | 
| 326 | 
            +
             | 
| 268 327 | 
             
                        #{str_arg_initialization}
         | 
| 269 328 | 
             
                        #{str_impl}
         | 
| 270 329 |  | 
| @@ -273,7 +332,8 @@ module FastRuby | |
| 273 332 | 
             
                    "
         | 
| 274 333 | 
             
                    }
         | 
| 275 334 |  | 
| 276 | 
            -
                    "rb_iterate(#{anonymous_function(caller_code)}, (VALUE) | 
| 335 | 
            +
                    protected_block("rb_iterate(#{anonymous_function(&caller_code)}, (VALUE)pframe, #{anonymous_function(&block_code)}, (VALUE)pframe)", true)
         | 
| 336 | 
            +
             | 
| 277 337 | 
             
                  elsif convention == :fastruby
         | 
| 278 338 |  | 
| 279 339 | 
             
                    str_arg_initialization = ""
         | 
| @@ -291,11 +351,37 @@ module FastRuby | |
| 291 351 | 
             
                    end
         | 
| 292 352 |  | 
| 293 353 | 
             
                    block_code = proc { |name| "
         | 
| 294 | 
            -
                      static VALUE #{name}(int argc, VALUE* argv, VALUE  | 
| 354 | 
            +
                      static VALUE #{name}(int argc, VALUE* argv, VALUE _locals, VALUE _parent_frame) {
         | 
| 295 355 | 
             
                        // block for call to #{call_tree[2]}
         | 
| 296 356 | 
             
                        VALUE last_expression = Qnil;
         | 
| 357 | 
            +
                        #{@frame_struct} frame;
         | 
| 358 | 
            +
                        #{@frame_struct} *pframe = (void*)&frame;
         | 
| 359 | 
            +
                        #{@frame_struct} *parent_frame = (void*)_parent_frame;
         | 
| 360 | 
            +
                        #{@locals_struct} *plocals;
         | 
| 361 | 
            +
             | 
| 362 | 
            +
                        frame.plocals = (void*)_locals;
         | 
| 363 | 
            +
                        frame.parent_frame = parent_frame;
         | 
| 364 | 
            +
                        frame.return_value = Qnil;
         | 
| 365 | 
            +
                        frame.target_frame = &frame;
         | 
| 366 | 
            +
                        frame.exception = Qnil;
         | 
| 367 | 
            +
                        frame.rescue = 0;
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                        plocals = frame.plocals;
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                        if (setjmp(frame.jmp) != 0) {
         | 
| 372 | 
            +
                            if (pframe->target_frame != pframe) {
         | 
| 373 | 
            +
                              if (pframe->target_frame == (void*)-3) {
         | 
| 374 | 
            +
                                 return pframe->return_value;
         | 
| 375 | 
            +
                              }
         | 
| 376 | 
            +
                              // raise exception
         | 
| 377 | 
            +
                              ((typeof(pframe))_parent_frame)->exception = pframe->exception;
         | 
| 378 | 
            +
                              ((typeof(pframe))_parent_frame)->target_frame = pframe->target_frame;
         | 
| 379 | 
            +
                              ((typeof(pframe))_parent_frame)->return_value = pframe->return_value;
         | 
| 380 | 
            +
                              longjmp(((typeof(pframe))_parent_frame)->jmp,1);
         | 
| 381 | 
            +
                            }
         | 
| 382 | 
            +
             | 
| 383 | 
            +
                        }
         | 
| 297 384 |  | 
| 298 | 
            -
                        #{str_lvar_initialization};
         | 
| 299 385 | 
             
                        #{str_arg_initialization}
         | 
| 300 386 | 
             
                        #{str_impl}
         | 
| 301 387 |  | 
| @@ -313,59 +399,60 @@ module FastRuby | |
| 313 399 |  | 
| 314 400 | 
             
                    if call_args_tree.size > 1
         | 
| 315 401 | 
             
                      value_cast = ( ["VALUE"]*(call_tree[3].size) ).join(",")
         | 
| 316 | 
            -
                      value_cast = value_cast + ", VALUE" if convention == :fastruby
         | 
| 402 | 
            +
                      value_cast = value_cast + ", VALUE, VALUE" if convention == :fastruby
         | 
| 317 403 |  | 
| 318 404 | 
             
                      str_called_code_args = call_tree[3][1..-1].map{|subtree| to_c subtree}.join(",")
         | 
| 319 405 |  | 
| 320 406 | 
             
                        caller_code = proc { |name| "
         | 
| 321 | 
            -
                          static VALUE #{name}(VALUE param) {
         | 
| 407 | 
            +
                          static VALUE #{name}(VALUE param, VALUE pframe) {
         | 
| 322 408 | 
             
                            #{@block_struct} block;
         | 
| 409 | 
            +
                            #{@locals_struct} *plocals = (void*)param;
         | 
| 323 410 |  | 
| 324 | 
            -
                            block.block_function_address = (void*)#{anonymous_function(block_code)};
         | 
| 411 | 
            +
                            block.block_function_address = (void*)#{anonymous_function(&block_code)};
         | 
| 325 412 | 
             
                            block.block_function_param = (void*)param;
         | 
| 326 413 |  | 
| 327 414 | 
             
                            // call to #{call_tree[2]}
         | 
| 328 415 |  | 
| 329 | 
            -
                            #{ | 
| 330 | 
            -
             | 
| 331 | 
            -
                            return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, #{str_called_code_args});
         | 
| 416 | 
            +
                            return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, (VALUE)pframe, #{str_called_code_args});
         | 
| 332 417 | 
             
                          }
         | 
| 333 418 | 
             
                        "
         | 
| 334 419 | 
             
                        }
         | 
| 335 420 |  | 
| 336 421 | 
             
                    else
         | 
| 337 422 | 
             
                        caller_code = proc { |name| "
         | 
| 338 | 
            -
                          static VALUE #{name}(VALUE param) {
         | 
| 423 | 
            +
                          static VALUE #{name}(VALUE param, VALUE pframe) {
         | 
| 339 424 | 
             
                            #{@block_struct} block;
         | 
| 425 | 
            +
                            #{@locals_struct} *plocals = (void*)param;
         | 
| 340 426 |  | 
| 341 | 
            -
                            block.block_function_address = (void*)#{anonymous_function(block_code)};
         | 
| 427 | 
            +
                            block.block_function_address = (void*)#{anonymous_function(&block_code)};
         | 
| 342 428 | 
             
                            block.block_function_param = (void*)param;
         | 
| 343 429 |  | 
| 344 430 | 
             
                            // call to #{call_tree[2]}
         | 
| 345 | 
            -
                            #{str_lvar_initialization}
         | 
| 346 431 |  | 
| 347 | 
            -
                            return ((VALUE(*)(VALUE,VALUE))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block);
         | 
| 432 | 
            +
                            return ((VALUE(*)(VALUE,VALUE,VALUE))0x#{address.to_s(16)})(#{str_recv}, (VALUE)&block, (VALUE)pframe);
         | 
| 348 433 | 
             
                          }
         | 
| 349 434 | 
             
                        "
         | 
| 350 435 | 
             
                        }
         | 
| 351 436 | 
             
                    end
         | 
| 352 437 |  | 
| 353 | 
            -
                    "#{anonymous_function(caller_code)}((VALUE) | 
| 438 | 
            +
                    "#{anonymous_function(&caller_code)}((VALUE)plocals, (VALUE)pframe)"
         | 
| 354 439 | 
             
                  end
         | 
| 355 440 | 
             
                end
         | 
| 356 441 |  | 
| 357 442 | 
             
                def to_c_yield(tree)
         | 
| 358 443 |  | 
| 359 444 | 
             
                  block_code = proc { |name| "
         | 
| 360 | 
            -
                    static VALUE #{name}(VALUE  | 
| 445 | 
            +
                    static VALUE #{name}(VALUE frame_param, VALUE* block_args) {
         | 
| 361 446 |  | 
| 362 447 | 
             
                      #{@locals_struct} *plocals;
         | 
| 363 | 
            -
                       | 
| 448 | 
            +
                      #{@frame_struct} *pframe;
         | 
| 449 | 
            +
                      pframe = (void*)frame_param;
         | 
| 450 | 
            +
                      plocals = (void*)pframe->plocals;
         | 
| 364 451 |  | 
| 365 452 | 
             
                      if (plocals->block_function_address == 0) {
         | 
| 366 453 | 
             
                        rb_raise(rb_eLocalJumpError, \"no block given\");
         | 
| 367 454 | 
             
                      } else {
         | 
| 368 | 
            -
                        return ((VALUE(*)(int,VALUE*,VALUE))plocals->block_function_address)(#{tree.size-1}, block_args, plocals->block_function_param);
         | 
| 455 | 
            +
                        return ((VALUE(*)(int,VALUE*,VALUE,VALUE))plocals->block_function_address)(#{tree.size-1}, block_args, plocals->block_function_param, (VALUE)pframe);
         | 
| 369 456 | 
             
                      }
         | 
| 370 457 | 
             
                    }
         | 
| 371 458 | 
             
                  "
         | 
| @@ -388,9 +475,9 @@ module FastRuby | |
| 388 475 | 
             
                  end
         | 
| 389 476 |  | 
| 390 477 | 
             
                  if tree.size > 1
         | 
| 391 | 
            -
                    anonymous_function(block_code)+"((VALUE) | 
| 478 | 
            +
                    anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){#{tree[1..-1].map{|subtree| to_c subtree}.join(",")}})"
         | 
| 392 479 | 
             
                  else
         | 
| 393 | 
            -
                    anonymous_function(block_code)+"((VALUE) | 
| 480 | 
            +
                    anonymous_function(&block_code)+"((VALUE)pframe, (VALUE[]){})"
         | 
| 394 481 | 
             
                  end
         | 
| 395 482 | 
             
                end
         | 
| 396 483 |  | 
| @@ -416,7 +503,41 @@ module FastRuby | |
| 416 503 | 
             
                end
         | 
| 417 504 |  | 
| 418 505 | 
             
                def to_c_return(tree)
         | 
| 419 | 
            -
                  " | 
| 506 | 
            +
                  "pframe->target_frame = ((typeof(pframe))plocals->pframe); plocals->return_value = #{to_c(tree[1])}; longjmp(pframe->jmp, 1);\n"
         | 
| 507 | 
            +
                end
         | 
| 508 | 
            +
             | 
| 509 | 
            +
                def to_c_break(tree)
         | 
| 510 | 
            +
                  if @on_block
         | 
| 511 | 
            +
                    inline_block(
         | 
| 512 | 
            +
                     "
         | 
| 513 | 
            +
                     pframe->target_frame = (void*)-2;
         | 
| 514 | 
            +
                     pframe->return_value = #{tree[1] ? to_c(tree[1]) : "Qnil"};
         | 
| 515 | 
            +
                     pframe->exception = Qnil;
         | 
| 516 | 
            +
                     longjmp(pframe->jmp,1);"
         | 
| 517 | 
            +
                     )
         | 
| 518 | 
            +
                  else
         | 
| 519 | 
            +
                    inline_block("
         | 
| 520 | 
            +
                        pframe->target_frame = (void*)-1;
         | 
| 521 | 
            +
                        pframe->exception = (VALUE)#{LocalJumpError.exception.internal_value};
         | 
| 522 | 
            +
                        longjmp(pframe->jmp,1);
         | 
| 523 | 
            +
                        return Qnil;
         | 
| 524 | 
            +
                        ")
         | 
| 525 | 
            +
             | 
| 526 | 
            +
                  end
         | 
| 527 | 
            +
                end
         | 
| 528 | 
            +
             | 
| 529 | 
            +
                def to_c_next(tree)
         | 
| 530 | 
            +
                  if @on_block
         | 
| 531 | 
            +
                   "Qnil; pframe->target_frame = (void*)-3; pframe->return_value = #{tree[1] ? to_c(tree[1]) : "Qnil"}; longjmp(pframe->jmp,1)"
         | 
| 532 | 
            +
                  else
         | 
| 533 | 
            +
                    inline_block("
         | 
| 534 | 
            +
                        pframe->target_frame = (void*)-1;
         | 
| 535 | 
            +
                        pframe->exception = (VALUE)#{LocalJumpError.exception.internal_value};
         | 
| 536 | 
            +
                        longjmp(pframe->jmp,1);
         | 
| 537 | 
            +
                        return Qnil;
         | 
| 538 | 
            +
                        ")
         | 
| 539 | 
            +
             | 
| 540 | 
            +
                  end
         | 
| 420 541 | 
             
                end
         | 
| 421 542 |  | 
| 422 543 | 
             
                def to_c_lit(tree)
         | 
| @@ -440,16 +561,18 @@ module FastRuby | |
| 440 561 | 
             
                    hash_aset_code << "rb_hash_aset(hash, #{strkey}, #{strvalue});"
         | 
| 441 562 | 
             
                  end
         | 
| 442 563 |  | 
| 443 | 
            -
                   | 
| 564 | 
            +
                  anonymous_function{ |name| "
         | 
| 444 565 | 
             
                    static VALUE #{name}(VALUE value_params) {
         | 
| 445 | 
            -
                      #{@ | 
| 566 | 
            +
                      #{@frame_struct} *pframe;
         | 
| 567 | 
            +
                      #{@locals_struct} *plocals;
         | 
| 568 | 
            +
                      pframe = (void*)value_params;
         | 
| 569 | 
            +
                      plocals = (void*)pframe->plocals;
         | 
| 570 | 
            +
             | 
| 446 571 | 
             
                      VALUE hash = rb_hash_new();
         | 
| 447 572 | 
             
                      #{hash_aset_code}
         | 
| 448 573 | 
             
                      return hash;
         | 
| 449 574 | 
             
                    }
         | 
| 450 | 
            -
                  " }
         | 
| 451 | 
            -
             | 
| 452 | 
            -
                  anonymous_function(wrapper_func) + "((VALUE)#{locals_pointer})"
         | 
| 575 | 
            +
                  " } + "((VALUE)pframe)"
         | 
| 453 576 | 
             
                end
         | 
| 454 577 |  | 
| 455 578 | 
             
                def to_c_array(tree)
         | 
| @@ -506,54 +629,178 @@ module FastRuby | |
| 506 629 | 
             
                  "rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value})"
         | 
| 507 630 | 
             
                end
         | 
| 508 631 |  | 
| 509 | 
            -
                def  | 
| 510 | 
            -
                   | 
| 511 | 
            -
                  args_tree = tree[2]
         | 
| 632 | 
            +
                def to_c_defs(tree)
         | 
| 633 | 
            +
                  args_tree = tree[3];
         | 
| 512 634 |  | 
| 513 | 
            -
                   | 
| 635 | 
            +
                  tmp = FastRuby.build_defs(tree)
         | 
| 636 | 
            +
             | 
| 637 | 
            +
                  extra_code << tmp[0]
         | 
| 514 638 |  | 
| 639 | 
            +
                  inline_block "
         | 
| 640 | 
            +
                    rb_define_singleton_method(#{to_c tree[1]}, \"#{tree[2].to_s}\", (void*)#{tmp[1]}, #{args_tree.size-1});
         | 
| 641 | 
            +
                    return Qnil;
         | 
| 642 | 
            +
                    "
         | 
| 643 | 
            +
                end
         | 
| 644 | 
            +
             | 
| 645 | 
            +
                def to_c_defined(tree)
         | 
| 646 | 
            +
                  nt = tree[1].node_type
         | 
| 647 | 
            +
             | 
| 648 | 
            +
                  if nt == :self
         | 
| 649 | 
            +
                  'rb_str_new2("self")'
         | 
| 650 | 
            +
                  elsif nt == :true
         | 
| 651 | 
            +
                  'rb_str_new2("true")'
         | 
| 652 | 
            +
                  elsif nt == :false
         | 
| 653 | 
            +
                  'rb_str_new2("false")'
         | 
| 654 | 
            +
                  elsif nt == :nil
         | 
| 655 | 
            +
                  'rb_str_new2("nil")'
         | 
| 656 | 
            +
                  elsif nt == :lvar
         | 
| 657 | 
            +
                  'rb_str_new2("local-variable")'
         | 
| 658 | 
            +
                  elsif nt == :gvar
         | 
| 659 | 
            +
                  "rb_gvar_defined((struct global_entry*)0x#{global_entry(tree[1][1]).to_s(16)}) ? #{"global-variable".internal_value} : Qnil"
         | 
| 660 | 
            +
                  elsif nt == :const
         | 
| 661 | 
            +
                  "rb_const_defined(rb_cObject, #{tree[1][1].to_i}) ? #{"constant".internal_value} : Qnil"
         | 
| 662 | 
            +
                  elsif nt == :call
         | 
| 663 | 
            +
                  "rb_method_node(CLASS_OF(#{to_c tree[1][1]}), #{tree[1][2].to_i}) ? #{"method".internal_value} : Qnil"
         | 
| 664 | 
            +
                  elsif nt == :yield
         | 
| 665 | 
            +
                    "rb_block_given_p() ? #{"yield".internal_value} : Qnil"
         | 
| 666 | 
            +
                  elsif nt == :ivar
         | 
| 667 | 
            +
                  "rb_ivar_defined(plocals->self,#{tree[1][1].to_i}) ? #{"instance-variable".internal_value} : Qnil"
         | 
| 668 | 
            +
                  elsif nt == :attrset or
         | 
| 669 | 
            +
                        nt == :op_asgn1 or
         | 
| 670 | 
            +
                        nt == :op_asgn2 or
         | 
| 671 | 
            +
                        nt == :op_asgn_or or
         | 
| 672 | 
            +
                        nt == :op_asgn_and or
         | 
| 673 | 
            +
                        nt == :op_asgn_masgn or
         | 
| 674 | 
            +
                        nt == :masgn or
         | 
| 675 | 
            +
                        nt == :lasgn or
         | 
| 676 | 
            +
                        nt == :dasgn or
         | 
| 677 | 
            +
                        nt == :dasgn_curr or
         | 
| 678 | 
            +
                        nt == :gasgn or
         | 
| 679 | 
            +
                        nt == :iasgn or
         | 
| 680 | 
            +
                        nt == :cdecl or
         | 
| 681 | 
            +
                        nt == :cvdecl or
         | 
| 682 | 
            +
                        nt == :cvasgn
         | 
| 683 | 
            +
                    "assignment".internal_value
         | 
| 684 | 
            +
                  else
         | 
| 685 | 
            +
                    "expression".internal_value
         | 
| 686 | 
            +
                  end
         | 
| 687 | 
            +
                end
         | 
| 688 | 
            +
             | 
| 689 | 
            +
                def initialize_method_structs(args_tree)
         | 
| 515 690 | 
             
                  @locals_struct = "struct {
         | 
| 516 | 
            -
                    #{@locals.map{|l| "VALUE #{l};\n"}.join}
         | 
| 517 | 
            -
                    #{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
         | 
| 518 691 | 
             
                    void* block_function_address;
         | 
| 519 692 | 
             
                    VALUE block_function_param;
         | 
| 693 | 
            +
                    jmp_buf jmp;
         | 
| 694 | 
            +
                    VALUE return_value;
         | 
| 695 | 
            +
                    void* pframe;
         | 
| 696 | 
            +
                    #{@locals.map{|l| "VALUE #{l};\n"}.join}
         | 
| 697 | 
            +
                    #{args_tree[1..-1].map{|arg| "VALUE #{arg};\n"}.join};
         | 
| 520 698 | 
             
                    }"
         | 
| 699 | 
            +
                end
         | 
| 521 700 |  | 
| 522 | 
            -
             | 
| 523 | 
            -
             | 
| 524 | 
            -
             | 
| 701 | 
            +
                def to_c_method_defs(tree)
         | 
| 702 | 
            +
             | 
| 703 | 
            +
                  method_name = tree[2]
         | 
| 704 | 
            +
                  args_tree = tree[3]
         | 
| 705 | 
            +
             | 
| 706 | 
            +
                  impl_tree = tree[4][1]
         | 
| 707 | 
            +
             | 
| 708 | 
            +
                  initialize_method_structs(args_tree)
         | 
| 709 | 
            +
             | 
| 710 | 
            +
                  strargs = if args_tree.size > 1
         | 
| 711 | 
            +
                    "VALUE self, void* block_address, VALUE block_param, void* _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
         | 
| 712 | 
            +
                  else
         | 
| 713 | 
            +
                    "VALUE self, void* block_address, VALUE block_param, void* _parent_frame"
         | 
| 714 | 
            +
                  end
         | 
| 715 | 
            +
             | 
| 716 | 
            +
                  extra_code << "static VALUE #{@alt_method_name + "_real"}(#{strargs}) {
         | 
| 717 | 
            +
                    #{func_frame}
         | 
| 718 | 
            +
             | 
| 719 | 
            +
                    #{args_tree[1..-1].map { |arg|
         | 
| 720 | 
            +
                      "locals.#{arg} = #{arg};\n"
         | 
| 721 | 
            +
                    }.join("") }
         | 
| 722 | 
            +
             | 
| 723 | 
            +
                    locals.block_function_address = block_address;
         | 
| 724 | 
            +
                    locals.block_function_param = block_param;
         | 
| 725 | 
            +
             | 
| 726 | 
            +
                    return #{to_c impl_tree};
         | 
| 525 727 | 
             
                  }"
         | 
| 526 728 |  | 
| 527 | 
            -
                   | 
| 528 | 
            -
             | 
| 529 | 
            -
                  if impl_tree[0] == :block
         | 
| 530 | 
            -
                    str_impl = to_c impl_tree
         | 
| 729 | 
            +
                  strargs2 = if args_tree.size > 1
         | 
| 730 | 
            +
                    "VALUE self, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
         | 
| 531 731 | 
             
                  else
         | 
| 532 | 
            -
                     | 
| 533 | 
            -
             | 
| 534 | 
            -
             | 
| 535 | 
            -
             | 
| 536 | 
            -
             | 
| 732 | 
            +
                    "VALUE self"
         | 
| 733 | 
            +
                  end
         | 
| 734 | 
            +
             | 
| 735 | 
            +
                  value_cast = ( ["VALUE"]*(args_tree.size+1) ).join(",")
         | 
| 736 | 
            +
                  strmethodargs = ""
         | 
| 737 | 
            +
             | 
| 738 | 
            +
                  if args_tree.size > 1
         | 
| 739 | 
            +
                    strmethodargs = "self,block_address,block_param,&frame,#{args_tree[1..-1].map(&:to_s).join(",") }"
         | 
| 740 | 
            +
                  else
         | 
| 741 | 
            +
                    strmethodargs = "self,block_address,block_param,&frame"
         | 
| 537 742 | 
             
                  end
         | 
| 538 743 |  | 
| 744 | 
            +
                  "
         | 
| 745 | 
            +
                  VALUE #{@alt_method_name}(#{strargs2}) {
         | 
| 746 | 
            +
                      #{@frame_struct} frame;
         | 
| 747 | 
            +
                      int argc = #{args_tree.size};
         | 
| 748 | 
            +
                      void* block_address = 0;
         | 
| 749 | 
            +
                      VALUE block_param = Qnil;
         | 
| 750 | 
            +
             | 
| 751 | 
            +
             | 
| 752 | 
            +
                      frame.plocals = 0;
         | 
| 753 | 
            +
                      frame.parent_frame = 0;
         | 
| 754 | 
            +
                      frame.return_value = Qnil;
         | 
| 755 | 
            +
                      frame.target_frame = &frame;
         | 
| 756 | 
            +
                      frame.exception = Qnil;
         | 
| 757 | 
            +
                      frame.rescue = 0;
         | 
| 758 | 
            +
             | 
| 759 | 
            +
                      if (rb_block_given_p()) {
         | 
| 760 | 
            +
                        block_address = #{
         | 
| 761 | 
            +
                          anonymous_function{|name|
         | 
| 762 | 
            +
                          "static VALUE #{name}(int argc, VALUE* argv, VALUE param) {
         | 
| 763 | 
            +
                            return rb_yield_splat(rb_ary_new4(argc,argv));
         | 
| 764 | 
            +
                          }"
         | 
| 765 | 
            +
                          }
         | 
| 766 | 
            +
                        };
         | 
| 767 | 
            +
             | 
| 768 | 
            +
                        block_param = 0;
         | 
| 769 | 
            +
                      }
         | 
| 770 | 
            +
             | 
| 771 | 
            +
                      int aux = setjmp(frame.jmp);
         | 
| 772 | 
            +
                      if (aux != 0) {
         | 
| 773 | 
            +
                        rb_funcall(self, #{:raise.to_i}, 1, frame.exception);
         | 
| 774 | 
            +
                      }
         | 
| 775 | 
            +
             | 
| 776 | 
            +
             | 
| 777 | 
            +
                      return #{@alt_method_name + "_real"}(#{strmethodargs});
         | 
| 778 | 
            +
                  }
         | 
| 779 | 
            +
                  "
         | 
| 780 | 
            +
                end
         | 
| 781 | 
            +
             | 
| 782 | 
            +
                def to_c_method(tree)
         | 
| 783 | 
            +
                  method_name = tree[1]
         | 
| 784 | 
            +
                  args_tree = tree[2]
         | 
| 785 | 
            +
             | 
| 786 | 
            +
                  impl_tree = tree[3][1]
         | 
| 787 | 
            +
             | 
| 788 | 
            +
                  initialize_method_structs(args_tree)
         | 
| 789 | 
            +
             | 
| 539 790 | 
             
                  strargs = if args_tree.size > 1
         | 
| 540 | 
            -
                    "VALUE block, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
         | 
| 791 | 
            +
                    "VALUE block, VALUE _parent_frame, #{args_tree[1..-1].map{|arg| "VALUE #{arg}" }.join(",") }"
         | 
| 541 792 | 
             
                  else
         | 
| 542 | 
            -
                    "VALUE block"
         | 
| 793 | 
            +
                    "VALUE block, VALUE _parent_frame"
         | 
| 543 794 | 
             
                  end
         | 
| 544 795 |  | 
| 545 796 | 
             
                  "VALUE #{@alt_method_name || method_name}(#{strargs}) {
         | 
| 546 | 
            -
             | 
| 547 | 
            -
                    #{ | 
| 548 | 
            -
                    #{@block_struct} *pblock;
         | 
| 549 | 
            -
                    VALUE last_expression = Qnil;
         | 
| 797 | 
            +
             | 
| 798 | 
            +
                    #{func_frame}
         | 
| 550 799 |  | 
| 551 800 | 
             
                    #{args_tree[1..-1].map { |arg|
         | 
| 552 801 | 
             
                      "locals.#{arg} = #{arg};\n"
         | 
| 553 802 | 
             
                    }.join("") }
         | 
| 554 803 |  | 
| 555 | 
            -
                    locals.self = self;
         | 
| 556 | 
            -
             | 
| 557 804 | 
             
                    pblock = (void*)block;
         | 
| 558 805 | 
             
                    if (pblock) {
         | 
| 559 806 | 
             
                      locals.block_function_address = pblock->block_function_address;
         | 
| @@ -563,7 +810,7 @@ module FastRuby | |
| 563 810 | 
             
                      locals.block_function_param = Qnil;
         | 
| 564 811 | 
             
                    }
         | 
| 565 812 |  | 
| 566 | 
            -
                    return #{ | 
| 813 | 
            +
                    return #{to_c impl_tree};
         | 
| 567 814 | 
             
                  }"
         | 
| 568 815 | 
             
                end
         | 
| 569 816 |  | 
| @@ -571,10 +818,6 @@ module FastRuby | |
| 571 818 | 
             
                  "plocals->"
         | 
| 572 819 | 
             
                end
         | 
| 573 820 |  | 
| 574 | 
            -
                def locals_pointer
         | 
| 575 | 
            -
                  "plocals"
         | 
| 576 | 
            -
                end
         | 
| 577 | 
            -
             | 
| 578 821 | 
             
                def to_c_gvar(tree)
         | 
| 579 822 | 
             
                  "rb_gvar_get((struct global_entry*)0x#{global_entry(tree[1]).to_s(16)})"
         | 
| 580 823 | 
             
                end
         | 
| @@ -632,7 +875,7 @@ module FastRuby | |
| 632 875 | 
             
                      }
         | 
| 633 876 |  | 
| 634 877 |  | 
| 635 | 
            -
                      "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(verify_type_function)}(#{to_c tree[2]}))"
         | 
| 878 | 
            +
                      "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]}))"
         | 
| 636 879 | 
             
                    else
         | 
| 637 880 | 
             
                      "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
         | 
| 638 881 | 
             
                    end
         | 
| @@ -688,16 +931,67 @@ module FastRuby | |
| 688 931 | 
             
                  "
         | 
| 689 932 | 
             
                end
         | 
| 690 933 |  | 
| 691 | 
            -
                def  | 
| 692 | 
            -
                   | 
| 693 | 
            -
             | 
| 694 | 
            -
             | 
| 934 | 
            +
                def to_c_rescue(tree)
         | 
| 935 | 
            +
                  if tree[1][0] == :resbody
         | 
| 936 | 
            +
                    else_tree = tree[2]
         | 
| 937 | 
            +
             | 
| 938 | 
            +
                    if else_tree
         | 
| 939 | 
            +
                      to_c else_tree
         | 
| 940 | 
            +
                    else
         | 
| 941 | 
            +
                      "Qnil"
         | 
| 942 | 
            +
                    end
         | 
| 943 | 
            +
                  else
         | 
| 944 | 
            +
                    resbody_tree = tree[2]
         | 
| 945 | 
            +
                    else_tree = tree[3]
         | 
| 946 | 
            +
             | 
| 947 | 
            +
                    frame(to_c(tree[1])+";","
         | 
| 948 | 
            +
                      if (CLASS_OF(frame.exception) == #{to_c(resbody_tree[1][1])})
         | 
| 949 | 
            +
                      {
         | 
| 950 | 
            +
                        // trap exception
         | 
| 951 | 
            +
                        ;original_frame->target_frame = &frame;
         | 
| 952 | 
            +
                         #{to_c(resbody_tree[2])};
         | 
| 953 | 
            +
                      }
         | 
| 954 | 
            +
                      ", else_tree ? to_c(else_tree) : nil, 1)
         | 
| 955 | 
            +
                  end
         | 
| 956 | 
            +
                end
         | 
| 957 | 
            +
             | 
| 958 | 
            +
                def to_c_ensure(tree)
         | 
| 959 | 
            +
                  if tree.size == 2
         | 
| 960 | 
            +
                    to_c tree[1]
         | 
| 961 | 
            +
                  else
         | 
| 962 | 
            +
                    ensured_code = to_c tree[2]
         | 
| 963 | 
            +
                    inline_block "
         | 
| 964 | 
            +
                      #{frame(to_c(tree[1]),ensured_code,ensured_code,1)};
         | 
| 965 | 
            +
                    "
         | 
| 966 | 
            +
                  end
         | 
| 967 | 
            +
                end
         | 
| 695 968 |  | 
| 969 | 
            +
                def to_c_call(tree)
         | 
| 696 970 | 
             
                  directive_code = directive(tree)
         | 
| 697 971 | 
             
                  if directive_code
         | 
| 698 972 | 
             
                    return directive_code
         | 
| 699 973 | 
             
                  end
         | 
| 700 974 |  | 
| 975 | 
            +
                  if tree[2] == :require
         | 
| 976 | 
            +
                    tree[2] = :fastruby_require
         | 
| 977 | 
            +
                  elsif tree[2] == :raise
         | 
| 978 | 
            +
                    # raise code
         | 
| 979 | 
            +
                    args = tree[3]
         | 
| 980 | 
            +
             | 
| 981 | 
            +
                    return inline_block("
         | 
| 982 | 
            +
                        pframe->target_frame = (void*)-1;
         | 
| 983 | 
            +
                        pframe->exception = rb_funcall(#{to_c args[1]}, #{:exception.to_i},0);
         | 
| 984 | 
            +
                        longjmp(pframe->jmp, 1);
         | 
| 985 | 
            +
                        return Qnil;
         | 
| 986 | 
            +
                        ")
         | 
| 987 | 
            +
                  end
         | 
| 988 | 
            +
             | 
| 989 | 
            +
                  recv = tree[1]
         | 
| 990 | 
            +
                  mname = tree[2]
         | 
| 991 | 
            +
                  args = tree[3]
         | 
| 992 | 
            +
             | 
| 993 | 
            +
                  mname = :require_fastruby if mname == :require
         | 
| 994 | 
            +
             | 
| 701 995 | 
             
                  strargs = args[1..-1].map{|arg| to_c arg}.join(",")
         | 
| 702 996 |  | 
| 703 997 | 
             
                  argnum = args.size - 1
         | 
| @@ -745,8 +1039,12 @@ module FastRuby | |
| 745 1039 | 
             
                      convention = :cruby
         | 
| 746 1040 | 
             
                    end
         | 
| 747 1041 |  | 
| 748 | 
            -
                    address =  | 
| 749 | 
            -
                    len =  | 
| 1042 | 
            +
                    address = nil
         | 
| 1043 | 
            +
                    len = 0
         | 
| 1044 | 
            +
                    if mobject
         | 
| 1045 | 
            +
                      address = getaddress(mobject)
         | 
| 1046 | 
            +
                      len = getlen(mobject)
         | 
| 1047 | 
            +
                    end
         | 
| 750 1048 |  | 
| 751 1049 | 
             
                    extraargs = ""
         | 
| 752 1050 | 
             
                    extraargs = ", Qfalse" if convention == :fastruby
         | 
| @@ -754,10 +1052,10 @@ module FastRuby | |
| 754 1052 | 
             
                    if address then
         | 
| 755 1053 | 
             
                      if argnum == 0
         | 
| 756 1054 | 
             
                        value_cast = "VALUE"
         | 
| 757 | 
            -
                        value_cast = value_cast + ", VALUE" if convention == :fastruby
         | 
| 1055 | 
            +
                        value_cast = value_cast + ", VALUE,VALUE" if convention == :fastruby
         | 
| 758 1056 |  | 
| 759 1057 | 
             
                        if convention == :fastruby
         | 
| 760 | 
            -
                          "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse)"
         | 
| 1058 | 
            +
                          "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, (VALUE)pframe)"
         | 
| 761 1059 | 
             
                        else
         | 
| 762 1060 |  | 
| 763 1061 | 
             
                          str_incall_args = nil
         | 
| @@ -771,28 +1069,28 @@ module FastRuby | |
| 771 1069 | 
             
                            str_incall_args = "recv"
         | 
| 772 1070 | 
             
                          end
         | 
| 773 1071 |  | 
| 774 | 
            -
                           | 
| 775 | 
            -
             | 
| 776 | 
            -
             | 
| 777 | 
            -
                               | 
| 778 | 
            -
                                //  | 
| 779 | 
            -
                                 | 
| 780 | 
            -
             | 
| 781 | 
            -
             | 
| 1072 | 
            +
                          protected_block(
         | 
| 1073 | 
            +
             | 
| 1074 | 
            +
                            anonymous_function{ |name| "
         | 
| 1075 | 
            +
                              static VALUE #{name}(VALUE recv) {
         | 
| 1076 | 
            +
                                // call to #{recvtype}##{mname}
         | 
| 1077 | 
            +
                                if (rb_block_given_p()) {
         | 
| 1078 | 
            +
                                  // no passing block, recall
         | 
| 1079 | 
            +
                                  return rb_funcall(recv, #{tree[2].to_i}, 0);
         | 
| 1080 | 
            +
                                } else {
         | 
| 1081 | 
            +
                                  return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
         | 
| 1082 | 
            +
                                }
         | 
| 782 1083 | 
             
                              }
         | 
| 783 | 
            -
                            }
         | 
| 784 | 
            -
                           | 
| 785 | 
            -
             | 
| 786 | 
            -
                          anonymous_function(wrapper_func) + "(#{to_c(recv)})"
         | 
| 787 | 
            -
             | 
| 1084 | 
            +
                            " } + "(#{to_c(recv)})"
         | 
| 1085 | 
            +
                          )
         | 
| 788 1086 | 
             
                        end
         | 
| 789 1087 | 
             
                      else
         | 
| 790 1088 | 
             
                        value_cast = ( ["VALUE"]*(args.size) ).join(",")
         | 
| 791 | 
            -
                        value_cast = value_cast + ", VALUE" if convention == :fastruby
         | 
| 1089 | 
            +
                        value_cast = value_cast + ", VALUE, VALUE" if convention == :fastruby
         | 
| 792 1090 |  | 
| 793 1091 | 
             
                        wrapper_func = nil
         | 
| 794 1092 | 
             
                        if convention == :fastruby
         | 
| 795 | 
            -
                          "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, #{strargs})"
         | 
| 1093 | 
            +
                          "((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{to_c recv}, Qfalse, (VALUE)pframe, #{strargs})"
         | 
| 796 1094 | 
             
                        else
         | 
| 797 1095 |  | 
| 798 1096 | 
             
                          str_incall_args = nil
         | 
| @@ -806,35 +1104,36 @@ module FastRuby | |
| 806 1104 | 
             
                            str_incall_args = "recv, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")}"
         | 
| 807 1105 | 
             
                          end
         | 
| 808 1106 |  | 
| 809 | 
            -
                           | 
| 810 | 
            -
             | 
| 811 | 
            -
             | 
| 812 | 
            -
                               | 
| 813 | 
            -
                                //  | 
| 814 | 
            -
                                 | 
| 815 | 
            -
             | 
| 816 | 
            -
             | 
| 1107 | 
            +
                          protected_block(
         | 
| 1108 | 
            +
             | 
| 1109 | 
            +
                            anonymous_function{ |name| "
         | 
| 1110 | 
            +
                              static VALUE #{name}(VALUE recv, #{ (1..argnum).map{|x| "VALUE _arg"+x.to_s }.join(",")} ) {
         | 
| 1111 | 
            +
                                // call to #{recvtype}##{mname}
         | 
| 1112 | 
            +
                                if (rb_block_given_p()) {
         | 
| 1113 | 
            +
                                  // no passing block, recall
         | 
| 1114 | 
            +
                                  return rb_funcall(recv, #{tree[2].to_i}, #{argnum}, #{ (1..argnum).map{|x| "_arg"+x.to_s }.join(",")});
         | 
| 1115 | 
            +
                                } else {
         | 
| 1116 | 
            +
                                  return ((VALUE(*)(#{value_cast}))0x#{address.to_s(16)})(#{str_incall_args});
         | 
| 1117 | 
            +
                                }
         | 
| 817 1118 | 
             
                              }
         | 
| 818 | 
            -
                            }
         | 
| 819 | 
            -
                           | 
| 820 | 
            -
             | 
| 821 | 
            -
                          anonymous_function(wrapper_func) + "(#{to_c(recv)}, #{strargs})"
         | 
| 1119 | 
            +
                            " } + "(#{to_c(recv)}, #{strargs})"
         | 
| 1120 | 
            +
                          )
         | 
| 822 1121 | 
             
                        end
         | 
| 823 1122 | 
             
                      end
         | 
| 824 1123 | 
             
                    else
         | 
| 825 1124 |  | 
| 826 1125 | 
             
                      if argnum == 0
         | 
| 827 | 
            -
                        "rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
         | 
| 1126 | 
            +
                        protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)")
         | 
| 828 1127 | 
             
                      else
         | 
| 829 | 
            -
                        "rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
         | 
| 1128 | 
            +
                        protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )")
         | 
| 830 1129 | 
             
                      end
         | 
| 831 1130 | 
             
                    end
         | 
| 832 1131 |  | 
| 833 1132 | 
             
                  else
         | 
| 834 1133 | 
             
                    if argnum == 0
         | 
| 835 | 
            -
                      "rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)"
         | 
| 1134 | 
            +
                      protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, 0)")
         | 
| 836 1135 | 
             
                    else
         | 
| 837 | 
            -
                      "rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )"
         | 
| 1136 | 
            +
                      protected_block("rb_funcall(#{to_c recv}, #{tree[2].to_i}, #{argnum}, #{strargs} )")
         | 
| 838 1137 | 
             
                    end
         | 
| 839 1138 | 
             
                  end
         | 
| 840 1139 | 
             
                end
         | 
| @@ -847,6 +1146,13 @@ module FastRuby | |
| 847 1146 |  | 
| 848 1147 | 
             
                end
         | 
| 849 1148 |  | 
| 1149 | 
            +
                def to_c_module(tree)
         | 
| 1150 | 
            +
                  inline_block("
         | 
| 1151 | 
            +
                    rb_funcall(plocals->self,#{:fastruby.to_i},1,(VALUE)#{tree.internal_value});
         | 
| 1152 | 
            +
                    return Qnil;
         | 
| 1153 | 
            +
                  ")
         | 
| 1154 | 
            +
                end
         | 
| 1155 | 
            +
             | 
| 850 1156 | 
             
                def to_c_while(tree)
         | 
| 851 1157 | 
             
                  inline_block("
         | 
| 852 1158 | 
             
                      while (#{to_c tree[1]}) {
         | 
| @@ -872,6 +1178,14 @@ module FastRuby | |
| 872 1178 | 
             
                  end
         | 
| 873 1179 | 
             
                end
         | 
| 874 1180 |  | 
| 1181 | 
            +
                def on_block
         | 
| 1182 | 
            +
                  old_on_block = @on_block
         | 
| 1183 | 
            +
                  @on_block = true
         | 
| 1184 | 
            +
                  return yield
         | 
| 1185 | 
            +
                ensure
         | 
| 1186 | 
            +
                  @on_block = old_on_block
         | 
| 1187 | 
            +
                end
         | 
| 1188 | 
            +
             | 
| 875 1189 | 
             
                def with_extra_inference(extra_inference)
         | 
| 876 1190 | 
             
                  previous_infer_lvar_map = @infer_lvar_map
         | 
| 877 1191 | 
             
                  begin
         | 
| @@ -900,33 +1214,225 @@ module FastRuby | |
| 900 1214 | 
             
                  elsif mname == :inline_c
         | 
| 901 1215 | 
             
                    code = args[1][1]
         | 
| 902 1216 |  | 
| 903 | 
            -
                     | 
| 1217 | 
            +
                    return anonymous_function{ |name| "
         | 
| 904 1218 | 
             
                       static VALUE #{name}(VALUE param) {
         | 
| 905 1219 | 
             
                        #{@locals_struct} *plocals = (void*)param;
         | 
| 906 1220 | 
             
                        #{code};
         | 
| 907 1221 | 
             
                        return Qnil;
         | 
| 908 1222 | 
             
                      }
         | 
| 909 1223 | 
             
                     "
         | 
| 910 | 
            -
                    }
         | 
| 911 | 
            -
             | 
| 912 | 
            -
                    return anonymous_function(caller_code)+"((VALUE)plocals)"
         | 
| 1224 | 
            +
                    }+"((VALUE)plocals)"
         | 
| 913 1225 | 
             
                  else
         | 
| 914 1226 | 
             
                    nil
         | 
| 915 1227 | 
             
                  end
         | 
| 916 1228 | 
             
                end
         | 
| 917 1229 |  | 
| 1230 | 
            +
                def inline_block_reference(arg)
         | 
| 1231 | 
            +
                  code = nil
         | 
| 1232 | 
            +
             | 
| 1233 | 
            +
                  if arg.instance_of? Sexp
         | 
| 1234 | 
            +
                    code = to_c(arg);
         | 
| 1235 | 
            +
                  else
         | 
| 1236 | 
            +
                    code = arg
         | 
| 1237 | 
            +
                  end
         | 
| 1238 | 
            +
             | 
| 1239 | 
            +
                  anonymous_function{ |name| "
         | 
| 1240 | 
            +
                    static VALUE #{name}(VALUE param) {
         | 
| 1241 | 
            +
                      #{@frame_struct} *pframe = (void*)param;
         | 
| 1242 | 
            +
                      #{@locals_struct} *plocals = (void*)pframe->plocals;
         | 
| 1243 | 
            +
                      VALUE last_expression = Qnil;
         | 
| 1244 | 
            +
             | 
| 1245 | 
            +
                      #{code};
         | 
| 1246 | 
            +
                      return last_expression;
         | 
| 1247 | 
            +
                      }
         | 
| 1248 | 
            +
                    "
         | 
| 1249 | 
            +
                  }
         | 
| 1250 | 
            +
                end
         | 
| 1251 | 
            +
             | 
| 918 1252 | 
             
                def inline_block(code)
         | 
| 919 | 
            -
                   | 
| 1253 | 
            +
                  anonymous_function{ |name| "
         | 
| 920 1254 | 
             
                    static VALUE #{name}(VALUE param) {
         | 
| 921 | 
            -
                      #{@ | 
| 1255 | 
            +
                      #{@frame_struct} *pframe = (void*)param;
         | 
| 1256 | 
            +
                      #{@locals_struct} *plocals = (void*)pframe->plocals;
         | 
| 922 1257 | 
             
                      VALUE last_expression = Qnil;
         | 
| 923 1258 |  | 
| 924 1259 | 
             
                      #{code}
         | 
| 925 1260 | 
             
                      }
         | 
| 926 1261 | 
             
                    "
         | 
| 927 | 
            -
                  }
         | 
| 1262 | 
            +
                  } + "((VALUE)pframe)"
         | 
| 1263 | 
            +
                end
         | 
| 1264 | 
            +
             | 
| 1265 | 
            +
                def inline_ruby(proced, parameter)
         | 
| 1266 | 
            +
                  "rb_funcall(#{proced.internal_value}, #{:call.to_i}, 1, #{parameter})"
         | 
| 1267 | 
            +
                end
         | 
| 1268 | 
            +
             | 
| 1269 | 
            +
                def wrapped_break_block(inner_code)
         | 
| 1270 | 
            +
                  frame("return " + inner_code, "
         | 
| 1271 | 
            +
                        if (original_frame->target_frame == (void*)-2) {
         | 
| 1272 | 
            +
                          return pframe->return_value;
         | 
| 1273 | 
            +
                        }
         | 
| 1274 | 
            +
                        ")
         | 
| 1275 | 
            +
                end
         | 
| 928 1276 |  | 
| 929 | 
            -
             | 
| 1277 | 
            +
                def protected_block(inner_code, always_rescue = false)
         | 
| 1278 | 
            +
                  wrapper_code = "
         | 
| 1279 | 
            +
                     if (pframe->last_error != Qnil) {
         | 
| 1280 | 
            +
                          if (CLASS_OF(pframe->last_error)==(VALUE)#{UnwindFastrubyFrame.internal_value}) {
         | 
| 1281 | 
            +
                          #{@frame_struct} *pframe = (void*)param;
         | 
| 1282 | 
            +
             | 
| 1283 | 
            +
                            pframe->target_frame = (void*)FIX2LONG(rb_ivar_get(pframe->last_error, #{:@target_frame.to_i}));
         | 
| 1284 | 
            +
                            pframe->exception = rb_ivar_get(pframe->last_error, #{:@ex.to_i});
         | 
| 1285 | 
            +
                            pframe->return_value = rb_ivar_get(pframe->last_error, #{:@return_value.to_i});
         | 
| 1286 | 
            +
             | 
| 1287 | 
            +
                           if (pframe->target_frame == (void*)-2) {
         | 
| 1288 | 
            +
                              return pframe->return_value;
         | 
| 1289 | 
            +
                           }
         | 
| 1290 | 
            +
             | 
| 1291 | 
            +
                            longjmp(pframe->jmp, 1);
         | 
| 1292 | 
            +
                            return Qnil;
         | 
| 1293 | 
            +
             | 
| 1294 | 
            +
                          } else {
         | 
| 1295 | 
            +
                            // raise emulation
         | 
| 1296 | 
            +
                              #{@frame_struct} *pframe = (void*)param;
         | 
| 1297 | 
            +
                              pframe->target_frame = (void*)-1;
         | 
| 1298 | 
            +
                              pframe->exception = pframe->last_error;
         | 
| 1299 | 
            +
                              longjmp(pframe->jmp, 1);
         | 
| 1300 | 
            +
                              return Qnil;
         | 
| 1301 | 
            +
                          }
         | 
| 1302 | 
            +
             | 
| 1303 | 
            +
                      }
         | 
| 1304 | 
            +
                  "
         | 
| 1305 | 
            +
                  rescue_code = "rb_rescue2(#{inline_block_reference "return #{inner_code};"},(VALUE)pframe,#{anonymous_function{|name| "
         | 
| 1306 | 
            +
                    static VALUE #{name}(VALUE param, VALUE error) {
         | 
| 1307 | 
            +
                        #{@frame_struct} *pframe = (void*)param;
         | 
| 1308 | 
            +
                        pframe->last_error = error;
         | 
| 1309 | 
            +
                      }
         | 
| 1310 | 
            +
                  "}}
         | 
| 1311 | 
            +
                  ,(VALUE)pframe, rb_eException,(VALUE)0)"
         | 
| 1312 | 
            +
             | 
| 1313 | 
            +
                  if always_rescue
         | 
| 1314 | 
            +
                    inline_block "
         | 
| 1315 | 
            +
                      pframe->last_error = Qnil;
         | 
| 1316 | 
            +
                      VALUE result = #{rescue_code};
         | 
| 1317 | 
            +
             | 
| 1318 | 
            +
                      #{wrapper_code}
         | 
| 1319 | 
            +
             | 
| 1320 | 
            +
                      return result;
         | 
| 1321 | 
            +
                    "
         | 
| 1322 | 
            +
                  else
         | 
| 1323 | 
            +
                    inline_block "
         | 
| 1324 | 
            +
                      VALUE result;
         | 
| 1325 | 
            +
                      pframe->last_error = Qnil;
         | 
| 1326 | 
            +
             | 
| 1327 | 
            +
                      if (pframe->rescue) {
         | 
| 1328 | 
            +
                        result = #{rescue_code};
         | 
| 1329 | 
            +
                      } else {
         | 
| 1330 | 
            +
                        return #{inner_code};
         | 
| 1331 | 
            +
                      }
         | 
| 1332 | 
            +
             | 
| 1333 | 
            +
                      #{wrapper_code}
         | 
| 1334 | 
            +
             | 
| 1335 | 
            +
                      return result;
         | 
| 1336 | 
            +
                    "
         | 
| 1337 | 
            +
                  end
         | 
| 1338 | 
            +
             | 
| 1339 | 
            +
                end
         | 
| 1340 | 
            +
             | 
| 1341 | 
            +
             | 
| 1342 | 
            +
                def func_frame
         | 
| 1343 | 
            +
                  "
         | 
| 1344 | 
            +
                    #{@locals_struct} locals;
         | 
| 1345 | 
            +
                    #{@locals_struct} *plocals = (void*)&locals;
         | 
| 1346 | 
            +
                    #{@frame_struct} frame;
         | 
| 1347 | 
            +
                    #{@frame_struct} *pframe;
         | 
| 1348 | 
            +
             | 
| 1349 | 
            +
                    frame.plocals = plocals;
         | 
| 1350 | 
            +
                    frame.parent_frame = (void*)_parent_frame;
         | 
| 1351 | 
            +
                    frame.return_value = Qnil;
         | 
| 1352 | 
            +
                    frame.target_frame = &frame;
         | 
| 1353 | 
            +
                    frame.exception = Qnil;
         | 
| 1354 | 
            +
                    frame.rescue = 0;
         | 
| 1355 | 
            +
             | 
| 1356 | 
            +
                    locals.pframe = &frame;
         | 
| 1357 | 
            +
             | 
| 1358 | 
            +
                    pframe = (void*)&frame;
         | 
| 1359 | 
            +
             | 
| 1360 | 
            +
                    #{@block_struct} *pblock;
         | 
| 1361 | 
            +
                    VALUE last_expression = Qnil;
         | 
| 1362 | 
            +
             | 
| 1363 | 
            +
                    int aux = setjmp(pframe->jmp);
         | 
| 1364 | 
            +
                    if (aux != 0) {
         | 
| 1365 | 
            +
             | 
| 1366 | 
            +
                      if (pframe->target_frame == (void*)-2) {
         | 
| 1367 | 
            +
                        return pframe->return_value;
         | 
| 1368 | 
            +
                      }
         | 
| 1369 | 
            +
             | 
| 1370 | 
            +
                      if (pframe->target_frame != pframe) {
         | 
| 1371 | 
            +
                        // raise exception
         | 
| 1372 | 
            +
                        ((typeof(pframe))_parent_frame)->exception = pframe->exception;
         | 
| 1373 | 
            +
                        ((typeof(pframe))_parent_frame)->target_frame = pframe->target_frame;
         | 
| 1374 | 
            +
                        ((typeof(pframe))_parent_frame)->return_value = pframe->return_value;
         | 
| 1375 | 
            +
                        longjmp(((typeof(pframe))_parent_frame)->jmp,1);
         | 
| 1376 | 
            +
                      }
         | 
| 1377 | 
            +
             | 
| 1378 | 
            +
                      return plocals->return_value;
         | 
| 1379 | 
            +
                    }
         | 
| 1380 | 
            +
             | 
| 1381 | 
            +
                    locals.self = self;
         | 
| 1382 | 
            +
                  "
         | 
| 1383 | 
            +
                end
         | 
| 1384 | 
            +
             | 
| 1385 | 
            +
                def frame(code, jmp_code, not_jmp_code = "", rescued = nil)
         | 
| 1386 | 
            +
             | 
| 1387 | 
            +
                  anonymous_function{ |name| "
         | 
| 1388 | 
            +
                    static VALUE #{name}(VALUE param) {
         | 
| 1389 | 
            +
                      VALUE last_expression;
         | 
| 1390 | 
            +
                      #{@frame_struct} frame, *pframe, *parent_frame;
         | 
| 1391 | 
            +
                      #{@locals_struct} *plocals;
         | 
| 1392 | 
            +
             | 
| 1393 | 
            +
                      parent_frame = (void*)param;
         | 
| 1394 | 
            +
             | 
| 1395 | 
            +
                      frame.parent_frame = (void*)param;
         | 
| 1396 | 
            +
                      frame.plocals = parent_frame->plocals;
         | 
| 1397 | 
            +
                      frame.target_frame = &frame;
         | 
| 1398 | 
            +
                      frame.rescue = #{rescued ? rescued : "parent_frame->rescue"};
         | 
| 1399 | 
            +
             | 
| 1400 | 
            +
                      plocals = frame.plocals;
         | 
| 1401 | 
            +
                      pframe = &frame;
         | 
| 1402 | 
            +
             | 
| 1403 | 
            +
                      int aux = setjmp(frame.jmp);
         | 
| 1404 | 
            +
                      if (aux != 0) {
         | 
| 1405 | 
            +
                        last_expression = pframe->return_value;
         | 
| 1406 | 
            +
             | 
| 1407 | 
            +
                        // restore previous frame
         | 
| 1408 | 
            +
                        typeof(pframe) original_frame = pframe;
         | 
| 1409 | 
            +
                        pframe = parent_frame;
         | 
| 1410 | 
            +
             | 
| 1411 | 
            +
                        #{jmp_code};
         | 
| 1412 | 
            +
             | 
| 1413 | 
            +
                        if (original_frame->target_frame != original_frame) {
         | 
| 1414 | 
            +
                          pframe->exception = original_frame->exception;
         | 
| 1415 | 
            +
                          pframe->target_frame = original_frame->target_frame;
         | 
| 1416 | 
            +
                          pframe->return_value = original_frame->return_value;
         | 
| 1417 | 
            +
             | 
| 1418 | 
            +
                          longjmp(pframe->jmp,1);
         | 
| 1419 | 
            +
                        }
         | 
| 1420 | 
            +
             | 
| 1421 | 
            +
                        return last_expression;
         | 
| 1422 | 
            +
                      }
         | 
| 1423 | 
            +
             | 
| 1424 | 
            +
                      #{code};
         | 
| 1425 | 
            +
             | 
| 1426 | 
            +
                      // restore previous frame
         | 
| 1427 | 
            +
                      typeof(pframe) original_frame = pframe;
         | 
| 1428 | 
            +
                      pframe = parent_frame;
         | 
| 1429 | 
            +
                      #{not_jmp_code};
         | 
| 1430 | 
            +
             | 
| 1431 | 
            +
                      return last_expression;
         | 
| 1432 | 
            +
             | 
| 1433 | 
            +
                      }
         | 
| 1434 | 
            +
                    "
         | 
| 1435 | 
            +
                  } + "((VALUE)pframe)"
         | 
| 930 1436 | 
             
                end
         | 
| 931 1437 |  | 
| 932 1438 | 
             
                inline :C  do |builder|
         |