예제 #1
0
  Array* Array::concat(STATE, Array* other) {
    if(!LANGUAGE_18_ENABLED(state)) {
      if(is_frozen_p()) return force_as<Array>(Primitives::failure());
    }

    native_int osize = other->size();

    if(osize == 0) return this;
    if(LANGUAGE_18_ENABLED(state)) {
      if(is_frozen_p()) return force_as<Array>(Primitives::failure());
    }

    if(osize == 1) {
      set(state, size(), other->get(state, 0));
      return this;
    }

    native_int new_size = size() + osize;
    Tuple* nt = Tuple::create(state, new_size);
    nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
    nt->copy_from(state, other->tuple(), other->start(), other->total(), total_);

    tuple(state, nt);
    start(state, Fixnum::from(0));
    total(state, Fixnum::from(new_size));

    return this;
  }
예제 #2
0
파일: time.cpp 프로젝트: Erreon/rubinius
  Time* Time::specific(STATE, Object* self, Integer* sec, Integer* nsec,
                       Object* gmt)
  {
    Time* tm = state->new_object<Time>(as<Class>(self));

    if(sizeof(time_t) == sizeof(long long)) {
      tm->seconds_ = sec->to_long_long();
      tm->nanoseconds_ = nsec->to_long_long();
    } else {
      tm->seconds_ = sec->to_native();
      tm->nanoseconds_ = nsec->to_native();
    }

    // Do a little overflow cleanup.
    if(tm->nanoseconds_ >= 1000000000) {
      tm->seconds_ += tm->nanoseconds_ / 1000000000;
      tm->nanoseconds_ %= 1000000000;
    }

    if(tm->nanoseconds_ < 0) {
      tm->seconds_ += NDIV(tm->nanoseconds_, 1000000000);
      tm->nanoseconds_ = NMOD(tm->nanoseconds_, 1000000000);
    }

    if(LANGUAGE_18_ENABLED(state)) {
      tm->nanoseconds_ -= (tm->nanoseconds_ % 1000);
    }

    tm->is_gmt(state, CBOOL(gmt) ? cTrue : cFalse);

    return tm;
  }
예제 #3
0
  Symbol* SymbolTable::lookup(STATE, const char* str, size_t length) {
    if(length == 0 && LANGUAGE_18_ENABLED(state)) {
      Exception::argument_error(state, "Cannot create a symbol from an empty string");
      return NULL;
    }

    return lookup(str, length);
  }
예제 #4
0
 void test_object() {
   TS_ASSERT_EQUALS(G(object)->class_object(state), G(klass));
   if(!LANGUAGE_18_ENABLED(state)) {
     TS_ASSERT_EQUALS(G(object)->superclass(), G(basicobject));
   } else {
     TS_ASSERT_EQUALS(G(object)->superclass(), cNil);
   }
   check_const(object, "Object");
 }
예제 #5
0
 String* Module::get_name(STATE) {
   if(module_name()->nil_p()) {
     if(LANGUAGE_18_ENABLED(state)) {
       return String::create(state, "");
     } else {
       return nil<String>();
     }
   } else {
     return module_name()->to_str(state);
   }
 }
예제 #6
0
  Fixnum* Regexp::options(STATE) {
    if(unlikely(!onig_data)) {
      Exception::argument_error(state, "Not properly initialized Regexp");
    }

    int result = ((int)onig_get_options(onig_data) & OPTION_MASK);

    if(LANGUAGE_18_ENABLED(state)) {
      if(fixed_encoding_) {
        result |= get_kcode_from_enc(onig_get_encoding(onig_data));
      }
    } else {
      if(fixed_encoding_) {
        result |= OPTION_FIXEDENCODING;
      }
      if(no_encoding_) {
        result |= OPTION_NOENCODING;
      }
    }

    return Fixnum::from(result);
  }
예제 #7
0
  Symbol* SymbolTable::lookup(STATE, String* str) {
    if(str->nil_p()) {
      Exception::argument_error(state, "Cannot look up Symbol from nil");
      return NULL;
    }

    // Since we also explicitly use the size, we can safely
    // use byte_address() here.
    const char* bytes = (const char*) str->byte_address();
    size_t size = str->byte_size();

    if(LANGUAGE_18_ENABLED(state)) {
      for(size_t i = 0; i < size; i++) {
        if(bytes[i] == 0) {
          Exception::argument_error(state,
              "cannot create a symbol from a string containing `\\0'");
          return NULL;
        }
      }
    }

    return lookup(state, bytes, size);
  }
예제 #8
0
파일: proc.cpp 프로젝트: AndrewVos/rubinius
  Object* Proc::call(STATE, CallFrame* call_frame, Arguments& args) {
    bool lambda_style = RTEST(lambda_);
    int flags = 0;

    // Check the arity in lambda mode
    if(lambda_style) {
      flags = CallFrame::cIsLambda;
      int total = block_->code()->total_args()->to_native();
      int required = block_->code()->required_args()->to_native();

      bool arity_ok = false;
      if(Fixnum* fix = try_as<Fixnum>(block_->code()->splat())) {
        switch(fix->to_native()) {
        case -2:
          arity_ok = true;
          break;
        case -4:
          // splat = -4 means { |(a, b)| }
          if(args.total() == 1) {
            Array* ary = 0;
            Object* obj = args.get_argument(0);

            if(!(ary = try_as<Array>(obj))) {
              if(RTEST(obj->respond_to(state, state->symbol("to_ary"), Qfalse))) {
                obj = obj->send(state, call_frame, state->symbol("to_ary"));
                if(!(ary = try_as<Array>(obj))) {
                  Exception::type_error(state, "to_ary must return an Array", call_frame);
                  return 0;
                }
              }
            }

            if(ary) args.use_argument(ary);
          }
          // fall through for arity check
        case -3:
          // splat = -3 is used to distinguish { |a, | } from { |a| }
          if(args.total() == (size_t)required) arity_ok = true;
          break;
        default:
          if(args.total() >= (size_t)required) {
            arity_ok = true;
          }
        }

      /* For blocks taking one argument { |a|  }, in 1.8, there is a warning
       * issued but no exception raised when less than or more than one
       * argument is passed. If more than one is passed, 'a' receives an Array
       * of all the arguments.
       */
      } else if(required == 1 && LANGUAGE_18_ENABLED(state)) {
        arity_ok = true;
      } else {
        arity_ok = args.total() <= (size_t)total &&
                   args.total() >= (size_t)required;
      }

      if(!arity_ok) {
        Exception* exc =
          Exception::make_argument_error(state, required, args.total(),
              state->symbol("__block__"));
        exc->locations(state, Location::from_call_stack(state, call_frame));
        state->thread_state()->raise_exception(exc);
        return NULL;
      }
    }

    Object* ret;
    if(bound_method_->nil_p()) {
      ret = block_->call(state, call_frame, args, flags);
    } else if(NativeMethod* nm = try_as<NativeMethod>(bound_method_)) {
      ret = nm->execute(state, call_frame, nm, G(object), args);
    } else {
      Dispatch dis(state->symbol("__yield__"));
      ret = dis.send(state, call_frame, args);
    }

    return ret;
  }
예제 #9
0
  /*
   * This is a primitive so #initialize_copy can work.
   */
  Regexp* Regexp::initialize(STATE, String* pattern, Fixnum* options) {
    const UChar *pat;
    const UChar *end;
    OnigErrorInfo err_info;
    OnigEncoding enc;

    OnigOptionType opts = options->to_native();

    if(LANGUAGE_18_ENABLED(state)) {
      int kcode = opts & KCODE_MASK;

      pat = (UChar*)pattern->byte_address();
      end = pat + pattern->byte_size();

      if(kcode == 0) {
        enc = pattern->get_encoding_kcode_fallback(state);
      } else {
        // Don't attempt to fix the encoding later, it's been specified by the
        // user.
        enc = get_enc_from_kcode(kcode);
        fixed_encoding_ = true;
      }
    } else {
      fixed_encoding_ = opts & OPTION_FIXEDENCODING;
      no_encoding_    = opts & OPTION_NOENCODING;

      Encoding* source_enc = pattern->encoding(state);

      switch(opts & KCODE_MASK) {
      case KCODE_NONE:
        source_enc = 0;
        no_encoding_ = true;
        break;
      case KCODE_EUC:
        source_enc = Encoding::find(state, "EUC-JP");
        fixed_encoding_ = true;
        break;
      case KCODE_SJIS:
        source_enc = Encoding::find(state, "Windows-31J");
        fixed_encoding_ = true;
        break;
      case KCODE_UTF8:
        source_enc = Encoding::utf8_encoding(state);
        fixed_encoding_ = true;
        break;
      }

      String* converted = pattern->convert_escaped(state, source_enc, fixed_encoding_);

      pat = (UChar*)converted->byte_address();
      end = pat + converted->byte_size();
      enc = source_enc->get_encoding();

      pattern = pattern->string_dup(state);
      pattern->encoding(state, source_enc);
    }

    utilities::thread::Mutex::LockGuard lg(state->shared().onig_lock());

    int err = onig_new(&this->onig_data, pat, end, opts & OPTION_MASK, enc, ONIG_SYNTAX_RUBY, &err_info);

    if(err != ONIG_NORMAL) {
      UChar onig_err_buf[ONIG_MAX_ERROR_MESSAGE_LEN];
      char err_buf[1024];
      onig_error_code_to_str(onig_err_buf, err, &err_info);
      snprintf(err_buf, 1024, "%s: %s", onig_err_buf, pat);

      Exception::regexp_error(state, err_buf);
      return 0;
    }

    this->source(state, pattern);

    int num_names = onig_number_of_names(this->onig_data);

    if(num_names == 0) {
      this->names(state, nil<LookupTable>());
    } else {
      struct _gather_data gd;
      gd.state = state;
      LookupTable* tbl = LookupTable::create(state);
      gd.tbl = tbl;
      onig_foreach_name(this->onig_data, (int (*)(const OnigUChar*, const OnigUChar*,int,int*,OnigRegex,void*))_gather_names, (void*)&gd);
      this->names(state, tbl);
    }

    make_managed(state);

    return this;
  }
예제 #10
0
  // Installed by default in BlockEnvironment::execute, it runs the bytecodes
  // for the block in the interpreter.
  //
  // Future code will detect hot blocks and queue them in the JIT, whereby the
  // JIT will install a newly minted machine function into ::execute.
  Object* BlockEnvironment::execute_interpreter(STATE, CallFrame* previous,
                            BlockEnvironment* env, Arguments& args,
                            BlockInvocation& invocation)
  {
    // Don't use env->machine_code() because it might lock and the work should
    // already be done.
    MachineCode* const mcode = env->compiled_code_->machine_code();

    if(!mcode) {
      Exception::internal_error(state, previous, "invalid bytecode method");
      return 0;
    }

#ifdef ENABLE_LLVM
    if(mcode->call_count >= 0) {
      if(mcode->call_count >= state->shared().config.jit_call_til_compile) {
        LLVMState* ls = LLVMState::get(state);

        GCTokenImpl gct;
        OnStack<1> os(state, env);
        ls->compile_soon(state, gct, env->compiled_code(), previous,
                         invocation.self->lookup_begin(state), env, true);

      } else {
        mcode->call_count++;
      }
    }
#endif

    StackVariables* scope = ALLOCA_STACKVARIABLES(mcode->number_of_locals);

    Module* mod = invocation.module;
    if(!mod) mod = env->module();
    scope->initialize(invocation.self, env->top_scope_->block(),
                      mod, mcode->number_of_locals);
    scope->set_parent(env->scope_);

    InterpreterCallFrame* frame = ALLOCA_CALLFRAME(mcode->stack_size);

    frame->prepare(mcode->stack_size);

    frame->previous = previous;
    frame->constant_scope_ = invocation.constant_scope;

    frame->arguments = &args;
    frame->dispatch_data = env;
    frame->compiled_code = env->compiled_code_;
    frame->scope = scope;
    frame->top_scope_ = env->top_scope_;
    frame->flags = invocation.flags | CallFrame::cCustomConstantScope
                                    | CallFrame::cMultipleScopes
                                    | CallFrame::cBlock;

    // TODO: this is a quick hack to process block arguments in 1.9.
    if(!LANGUAGE_18_ENABLED(state)) {
      if(!GenericArguments::call(state, frame, mcode, scope, args, invocation.flags)) {
        return NULL;
      }
    }

#ifdef RBX_PROFILER
    if(unlikely(state->vm()->tooling())) {
      Module* mod = scope->module();
      if(SingletonClass* sc = try_as<SingletonClass>(mod)) {
        if(Module* ma = try_as<Module>(sc->attached_instance())) {
          mod = ma;
        }
      }

      OnStack<2> os(state, env, mod);

      // Check the stack and interrupts here rather than in the interpreter
      // loop itself.

      GCTokenImpl gct;

      if(!state->check_interrupts(gct, frame, frame)) return NULL;

      state->checkpoint(gct, frame);

      tooling::BlockEntry method(state, env, mod);
      return (*mcode->run)(state, mcode, frame);
    } else {
      // Check the stack and interrupts here rather than in the interpreter
      // loop itself.

      GCTokenImpl gct;

      if(!state->check_interrupts(gct, frame, frame)) return NULL;

      state->checkpoint(gct, frame);
      return (*mcode->run)(state, mcode, frame);
    }
#else
    // Check the stack and interrupts here rather than in the interpreter
    // loop itself.

    GCTokenImpl gct;

    if(!state->check_interrupts(gct, frame, frame)) return NULL;

    state->checkpoint(gct, frame);
    return (*mcode->run)(state, mcode, frame);
#endif
  }
예제 #11
0
  // Installed by default in BlockEnvironment::execute, it runs the bytecodes
  // for the block in the interpreter.
  //
  // Future code will detect hot blocks and queue them in the JIT, whereby the
  // JIT will install a newly minted machine function into ::execute.
  Object* BlockEnvironment::execute_interpreter(STATE, CallFrame* previous,
                            BlockEnvironment* env, Arguments& args,
                            BlockInvocation& invocation)
  {
    // Don't use env->vmmethod() because it mighc lock and the work should already
    // be done.
    VMMethod* const vmm = env->code_->backend_method();

    if(!vmm) {
      Exception::internal_error(state, previous, "invalid bytecode method");
      return 0;
    }

#ifdef ENABLE_LLVM
    if(vmm->call_count >= 0) {
      if(vmm->call_count >= state->shared().config.jit_call_til_compile) {
        LLVMState* ls = LLVMState::get(state);

        ls->compile_soon(state, env->code(), env, true);

      } else {
        vmm->call_count++;
      }
    }
#endif

    size_t scope_size = sizeof(StackVariables) +
                         (vmm->number_of_locals * sizeof(Object*));

    StackVariables* scope =
      reinterpret_cast<StackVariables*>(alloca(scope_size));

    Module* mod = invocation.module;
    if(!mod) mod = env->module();
    scope->initialize(invocation.self, env->top_scope_->block(),
                      mod, vmm->number_of_locals);
    scope->set_parent(env->scope_);

    InterpreterCallFrame* frame = ALLOCA_CALLFRAME(vmm->stack_size);

    frame->prepare(vmm->stack_size);

    frame->previous = previous;
    frame->static_scope_ = invocation.static_scope;

    frame->arguments = &args;
    frame->dispatch_data = reinterpret_cast<BlockEnvironment*>(env);
    frame->cm =       env->code_;
    frame->scope =    scope;
    frame->top_scope_ = env->top_scope_;
    frame->flags =    invocation.flags | CallFrame::cCustomStaticScope
                                       | CallFrame::cMultipleScopes
                                       | CallFrame::cBlock;
    frame->stack_top_ptr_ptr = NULL;

    // TODO: this is a quick hack to process block arguments in 1.9.
    if(!LANGUAGE_18_ENABLED(state)) {
      if(!GenericArguments::call(state, frame, vmm, scope, args, invocation.flags)) {
        return NULL;
      }
    }

    // Check the stack and interrupts here rather than in the interpreter
    // loop itself.

    GCTokenImpl gct;

    if(state->detect_stack_condition(frame)) {
      if(!state->check_interrupts(gct, frame, frame)) return NULL;
    }

    state->checkpoint(gct, frame);

#ifdef RBX_PROFILER
    if(unlikely(state->vm()->tooling())) {
      Module* mod = scope->module();
      if(SingletonClass* sc = try_as<SingletonClass>(mod)) {
        if(Module* ma = try_as<Module>(sc->attached_instance())) {
          mod = ma;
        }
      }

      tooling::BlockEntry method(state, env, mod);
      return (*vmm->run)(state, vmm, frame);
    } else {
      return (*vmm->run)(state, vmm, frame);
    }
#else
    return (*vmm->run)(state, vmm, frame);
#endif
  }
예제 #12
0
파일: integer.cpp 프로젝트: Groogy/rubinius
  Integer* Integer::from_cstr(STATE, const char* str, int base,
                              Object* strict)
  {
    bool negative = false;
    Integer* value = Fixnum::from(0);

    if(base == 1 || base > 36) return nil<Integer>();

    // Skip any combination of leading whitespace and underscores.
    // Leading whitespace is OK in strict mode, but underscores are not.
    while(isspace(*str) || *str == '_') {
      if(*str == '_') {
        if(strict == cTrue) {
          return nil<Integer>();
        } else if(!LANGUAGE_18_ENABLED(state)) {
          return value;
        }
      }

      str++;
    }

    if(*str == '-') {
      str++;
      negative = true;
    } else if(*str == '+') {
      str++;
    }

    char chr;
    int detected_base = 0;
    const char* str_start = str;

    // Try and detect a base prefix on the front. We have to do this
    // even though we might have been told the base, because we have
    // to know if we should discard the bytes that make up the prefix
    // if it's redundant with passed in base.
    //
    // For example, if base == 16 and str == "0xa", we return
    // to return 10. But if base == 10 and str == "0xa", we fail
    // because we rewind and try to process 0x as part of the
    // base 10 string.
    //
    if(*str == '0') {
      str++;
      switch(chr = *str++) {
      case 'b': case 'B':
        detected_base = 2;
        break;
      case 'o': case 'O':
        detected_base = 8;
        break;
      case 'd': case 'D':
        detected_base = 10;
        break;
      case 'x': case 'X':
        detected_base = 16;
        break;
      default:
        // If passed "017" and a base of 0, that is octal 15.
        // Otherwise, it is whatever those digits would be in the
        // specified base.
        str--;
        detected_base = 8;
      }
    }

    // If base is less than 0, then it's just a hint for how to process it
    // if there is no base detected.
    if(base < 0) {
      if(detected_base == 0) {
        // Ok, no detected because, use the base hint and start over.
        base = -base;
        str = str_start;
      } else {
        base = detected_base;
      }

    // If 0 was passed in as the base, we use the detected base.
    } else if(base == 0) {

      // Default to 10 if there is no input and no detected base.
      if(detected_base == 0) {
        base = 10;
        str = str_start;

      } else {
        base = detected_base;
      }

    // If the passed in base and the detected base contradict
    // each other, then rewind and process the whole string as
    // digits of the passed in base.
    } else if(base != detected_base) {
      // rewind the stream, and try and consume the prefix as
      // digits in the number.
      str = str_start;
    }


    bool underscore = false;

    while(*str) {
      chr = *str++;

      // If we see space characters
      if(chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r') {

        // Eat them all
        while(chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r') {
          chr = *str++;
        }

        // If there is more stuff after the spaces, get out of dodge.
        if(chr) {
          if(strict == cTrue) {
            return nil<Integer>();
          } else {
            goto return_value;
          }
        }

        break;
      }

      // If it's an underscore, remember that. An underscore is valid iff
      // it followed by a valid character for this base.
      if(chr == '_') {
        if(underscore) {
          // Double underscore is forbidden in strict mode.
          if(strict == cTrue) {
            return nil<Integer>();
          } else {
            // Stop parse number after two underscores in a row
            goto return_value;
          }
        }
        underscore = true;
        continue;
      } else {
        underscore = false;
      }

      // We use A-Z (and a-z) here so we support up to base 36.
      if(chr >= '0' && chr <= '9') {
        chr -= '0';
      } else if(chr >= 'A' && chr <= 'Z') {
        chr -= ('A' - 10);
      } else if(chr >= 'a' && chr <= 'z') {
        chr -= ('a' - 10);
      } else {
        //Invalid character, stopping right here.
        if(strict == cTrue) {
          return nil<Integer>();
        } else {
          break;
        }
      }

      // Bail if the current chr is greater or equal to the base,
      // mean it's invalid.
      if(chr >= base) {
        if(strict == cTrue) {
          return nil<Integer>();
        } else {
          break;
        }
      }

      if(value != Fixnum::from(0)) {
        if(Fixnum *fix = try_as<Fixnum>(value)) {
          value = fix->mul(state, Fixnum::from(base));
        } else {
          value = as<Bignum>(value)->mul(state, Fixnum::from(base));
        }
      }

      if(Fixnum *fix = try_as<Fixnum>(value)) {
        value = fix->add(state, Fixnum::from(chr));
      } else {
        value = as<Bignum>(value)->add(state, Fixnum::from(chr));
      }
    }

    // If we last saw an underscore and we're strict, bail.
    if(underscore && strict == cTrue) {
      return nil<Integer>();
    }

return_value:
    if(negative) {
      if(Fixnum* fix = try_as<Fixnum>(value)) {
        value = fix->neg(state);
      } else {
        value = as<Bignum>(value)->neg(state);
      }
    }

    return value;

  }
예제 #13
0
  Object* BlockAsMethod::block_executor(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
                                       Arguments& args)
  {
    BlockAsMethod* bm = as<BlockAsMethod>(exec);

    Fixnum* splat = bm->block_env()->compiled_code()->splat();
    size_t required = bm->block_env()->compiled_code()->required_args()->to_native();
    size_t total_args = bm->block_env()->compiled_code()->total_args()->to_native();

    /*
     * These are the block shapes, required args, and splat that we may see,
     * along with the arity check that we must perform:
     *
     *   block shape   required args   splat   check
     *  -------------|---------------|-------|-------
     *  { || }       |  0            |  nil  |  ==
     *  {  }         |  0            |  -2   |  none
     *  { |a| }      |  1            |  nil  |  none (1.8), == (>= 1.9)
     *  { |*a| }     |  0            |  0    |  none
     *  { |a, b| }   |  2            |  nil  |  ==
     *  { |a, *b| }  |  1            |  1    |  >=
     *
     * NOTE that when taking one argument, any arguments passed are put
     * into an array and the local gets the array (or an empty array if
     * no arguments are passed). This is handled by the bytecode prologue
     * of the block.
     */
    bool exception = false;
    size_t expected = 0;
    if(splat->nil_p()) {
      if((!LANGUAGE_18_ENABLED(state) || required != 1)) {
        if(args.total() > total_args) {
          exception = true;
          expected = total_args;
        }
        if(args.total() < required) {
          exception = true;
          expected = required;
        }
      }
    } else {
      if(required > args.total()) {
        exception = true;
        expected = required;
      }
    }

    if(exception) {
      Exception* exc =
        Exception::make_argument_error(state, expected, args.total(), args.name());
      exc->locations(state, Location::from_call_stack(state, call_frame));
      state->raise_exception(exc);
      return NULL;
    }

    BlockInvocation invocation(args.recv(),
        bm->block_env()->compiled_code()->scope(),
        CallFrame::cIsLambda | CallFrame::cBlockAsMethod);

    invocation.module = mod;

    return bm->block_env()->invoke(state, call_frame,
                                   bm->block_env(), args, invocation);
  }