예제 #1
0
  CallFrame* LLVMState::find_candidate(CompiledMethod* start, CallFrame* call_frame) {
    if(!config_.jit_inline_generic) {
      return call_frame;
    }

    int depth = cInlineMaxDepth;

    if(!start) {
      start = call_frame->cm;
      call_frame = call_frame->previous;
      depth--;
    }

    if(!call_frame || start->backend_method()->total > SMALL_METHOD_SIZE) {
      return call_frame;
    }

    CallFrame* caller = call_frame;

    while(depth-- > 0) {
      CompiledMethod* cur = call_frame->cm;
      VMMethod* vmm = cur->backend_method();

      /*
      if(call_frame->block_p()
          || vmm->required_args != vmm->total_args // has a splat
          || vmm->call_count < 200 // not called much
          || vmm->jitted() // already jitted
          || vmm->parent() // is a block
        ) return caller;
      */

      if(vmm->required_args != vmm->total_args // has a splat
          || vmm->call_count < 200 // not called much
          || vmm->jitted() // already jitted
          || !vmm->no_inline_p() // method marked as not inlinable
        ) return caller;

      CallFrame* next = call_frame->previous;

      if(!next|| cur->backend_method()->total > SMALL_METHOD_SIZE) return call_frame;

      caller = call_frame;
      call_frame = next;
    }

    return caller;
  }
예제 #2
0
  Location* Location::create(STATE, CallFrame* call_frame,
                             bool include_variables)
  {
    if(NativeMethodFrame* nmf = call_frame->native_method_frame()) {
      return create(state, nmf);
    }

    Location* loc = state->new_object<Location>(G(location));
    loc->method_module(state, call_frame->module());
    loc->receiver(state, call_frame->self());
    loc->method(state, call_frame->cm);
    loc->ip(state, Fixnum::from(call_frame->ip()));
    loc->flags(state, Fixnum::from(0));

    if(call_frame->is_block_p(state)) {
      loc->name(state, call_frame->top_scope(state)->method()->name());
      loc->set_is_block(state);
    } else {
      loc->name(state, call_frame->name());
    }

    VMMethod* vmm = call_frame->cm->backend_method();
    if(vmm && vmm->jitted()) {
      loc->set_is_jit(state);
    }

    if(include_variables) {
      // Use promote_scope because it can figure out of the generated
      // VariableScope should be isolated by default (true atm for JITd
      // frames)
      loc->variables(state, call_frame->promote_scope(state));
    }

    loc->static_scope(state, call_frame->static_scope());

    return loc;
  }
예제 #3
0
  Location* Location::create(STATE, CallFrame* call_frame) {
    Location* loc = state->new_object<Location>(G(location));
    loc->method_module(state, call_frame->module());
    loc->receiver(state, call_frame->self());
    loc->method(state, call_frame->cm);
    loc->ip(state, Fixnum::from(call_frame->ip() - 1));

    if(call_frame->is_block_p(state)) {
      loc->name(state, call_frame->top_scope(state)->method()->name());
      loc->is_block(state, Qtrue);
    } else {
      loc->name(state, call_frame->name());
      loc->is_block(state, Qfalse);
    }

    VMMethod* vmm = call_frame->cm->backend_method();
    if(vmm && vmm->jitted()) {
      loc->is_jit(state, Qtrue);
    } else {
      loc->is_jit(state, Qfalse);
    }

    return loc;
  }
예제 #4
0
  VMMethod* LLVMState::find_candidate(VMMethod* start, CallFrame* call_frame) {
    VMMethod* found = start;
    int depth = 0;
    bool consider_block_parents = config_.jit_inline_blocks;

    // No upper call_frames or generic inlining is off, use the start.
    // With generic inlining off, there is no way to inline back to start,
    // so we don't both trying.
    if(!config_.jit_inline_generic) {
      if(!start) start = call_frame->cm->backend_method();
      return find_first_non_block(call_frame);
    }

    /*
    std::cerr << "JIT target search:\n";

    if(start) {
      show_method(this, start);
    } else {
      std::cerr << "  <primitive>\n";
    }
    */

    VMMethod* next = call_frame->cm->backend_method();
    VMMethod* parent = 0;

    while(depth < cInlineMaxDepth) {
      // show_method(this, next);

      // Basic requirements
      if(next->required_args != next->total_args ||
          next->call_count < 200 ||
          next->jitted()) break;

      // Jump to defining methods of blocks?
      parent = next->parent();
      if(parent) {
        if(consider_block_parents) {
          // See if parent is in this call_frame chain properly..
          if(CallFrame* pf = validate_block_parent(call_frame, parent)) {
            depth++;

            // Method parents are valuable, so always use them if we find them.
            if(!parent->parent()) {
              found = parent;
            }
            // show_method(this, parent, " parent!");

            call_frame = pf;
          }
        } else {
          // We hit a block, just bail.
          break;
        }
      } else {
        found = next;
      }

      call_frame = call_frame->previous;
      if(!call_frame) break;

      next = call_frame->cm->backend_method();

      depth++;
    }

    if(!found && !next->parent()) return next;

    return found;
  }
예제 #5
0
  CallFrame* LLVMState::find_candidate(STATE, CompiledMethod* start, CallFrame* call_frame) {
    if(!config_.jit_inline_generic) {
      return call_frame;
    }

    int depth = cInlineMaxDepth;

    if(!start) rubinius::bug("null start");
    if(!call_frame) rubinius::bug("null call_frame");

    // if(!start) {
      // start = call_frame->cm;
      // call_frame = call_frame->previous;
      // depth--;
    // }

    if(debug_search) {
      std::cout << "> call_count: " << call_frame->cm->backend_method()->call_count
            << " size: " << call_frame->cm->backend_method()->total
            << " sends: " << call_frame->cm->backend_method()->inline_cache_count()
            << std::endl;

      call_frame->print_backtrace(state, 1);
    }

    if(start->backend_method()->total > (size_t)config_.jit_max_method_inline_size) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method isn't small: "
              << start->backend_method()->total << " > "
              << config_.jit_max_method_inline_size
              << std::endl;
      }

      return call_frame;
    }

    VMMethod* vmm = start->backend_method();

    if(vmm->required_args != vmm->total_args) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method req_args != total_args" << std::endl;
      }

      return call_frame;
    }

    if(vmm->no_inline_p()) {
      if(debug_search) {
        std::cout << "JIT: STOP. reason: trigger method no_inline_p() = true" << std::endl;
      }

      return call_frame;
    }

    CallFrame* callee = call_frame;
    call_frame = call_frame->previous;

    if(!call_frame) return callee;

    // Now start looking at callers.

    while(depth-- > 0) {
      CompiledMethod* cur = call_frame->cm;

      if(!cur) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: synthetic CallFrame hit" << std::endl;
        }
        return callee;
      }

      VMMethod* vmm = cur->backend_method();

      if(debug_search) {
        std::cout << "> call_count: " << vmm->call_count
              << " size: " << vmm->total
              << " sends: " << vmm->inline_cache_count()
              << std::endl;

        call_frame->print_backtrace(state, 1);
      }


      /*
      if(call_frame->block_p()
          || vmm->required_args != vmm->total_args // has a splat
          || vmm->call_count < 200 // not called much
          || vmm->jitted() // already jitted
          || vmm->parent() // is a block
        ) return callee;
      */

      if(vmm->required_args != vmm->total_args) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: req_args != total_args" << std::endl;
        }
        return callee;
      }

      if(vmm->call_count < config_.jit_call_inline_threshold) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: call_count too small: "
                << vmm->call_count << " < "
                << config_.jit_call_inline_threshold << std::endl;
        }

        return callee;
      }

      if(vmm->jitted()) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: already jitted" << std::endl;
        }

        return callee;
      }

      if(vmm->no_inline_p()) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: no_inline_p() = true" << std::endl;
        }

        return callee;
      }

      if(vmm->inline_cache_count() > eMaxInlineSendCount) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: high send count" << std::endl;
        }

        return call_frame;
      }

      // if(vmm->required_args != vmm->total_args // has a splat
          // || vmm->call_count < 200 // not called much
          // || vmm->jitted() // already jitted
          // || !vmm->no_inline_p() // method marked as not inlineable
        // ) return callee;

      CallFrame* prev = call_frame->previous;

      if(!prev) {
        if(debug_search) {
          std::cout << "JIT: STOP. reason: toplevel method" << std::endl;
        }
        return call_frame;
      }

      // if(cur->backend_method()->total > SMALL_METHOD_SIZE) {
        // if(debug_search) {
          // std::cout << "JIT: STOP. reason: big method: "
                // << cur->backend_method()->total << " > "
                // << SMALL_METHOD_SIZE
                // << "\n";
        // }

        // return call_frame;
      // }

      // if(!next || cur->backend_method()->total > SMALL_METHOD_SIZE) return call_frame;

      callee->cm->backend_method()->call_count = 0;

      callee = call_frame;
      call_frame = prev;
    }

    return callee;
  }