Esempio n. 1
0
  String* MatchData::matched_string(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    native_int max = source_->byte_size();
    native_int f = fin->to_native();
    native_int b = beg->to_native();

    String* string;

    if(!beg || !fin ||
        f > max || b > max || b < 0) {
      string = String::create(state, 0, 0);
    } else {
      const char* str = (char*)source_->byte_address();
      native_int sz = fin->to_native() - beg->to_native();

      string = String::create(state, str + beg->to_native(), sz);
    }

    source_->infect(state, string);
    string->encoding_from(state, source_);
    string->klass(state, source_->class_object(state));
    
    return string;
  }
Esempio n. 2
0
  Object* MatchData::nth_capture(STATE, native_int which) {
    if(region_->num_fields() <= which) return cNil;

    Tuple* sub = try_as<Tuple>(region_->at(state, which));
    if(!sub) return cNil;

    Fixnum* beg = try_as<Fixnum>(sub->at(state, 0));
    Fixnum* fin = try_as<Fixnum>(sub->at(state, 1));

    native_int b = beg->to_native();
    native_int f = fin->to_native();
    native_int max = source_->byte_size();

    if(!beg || !fin ||
        f > max ||
        b < 0) {
      return cNil;
    }

    const char* str = (char*)source_->byte_address();
    native_int sz = f - b;

    if(sz > max) sz = max;

    String* string = String::create(state, str + b, sz);
    string->encoding(state, source_->encoding());

    return string;
  }
Esempio n. 3
0
  String* MatchData::pre_matched(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));

    if(!beg || beg->to_native() <= 0) {
      return String::create(state, 0, 0);
    }

    const char* str = source_->c_str();
    native_int sz = beg->to_native();

    return String::create(state, str, sz);
  }
Esempio n. 4
0
  String* MatchData::post_matched(STATE) {
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    if(!fin || fin->to_native() >= source_->size()) {
      return String::create(state, 0, 0);
    }

    const char* str = source_->c_str();
    native_int sz = (native_int)source_->size() - fin->to_native();

    return String::create(state, str + fin->to_native(), sz);
  }
Esempio n. 5
0
  String* MatchData::matched_string(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    if(!beg || !fin ||
        fin->to_native() > source_->size() ||
        beg->to_native() < 0) {
      return String::create(state, 0, 0);
    }

    const char* str = source_->c_str();
    native_int sz = fin->to_native() - beg->to_native();

    return String::create(state, str + beg->to_native(), sz);
  }
Esempio n. 6
0
  void test_add() {
    Fixnum* one = Fixnum::from(1);
    Fixnum* two = as<Fixnum>(one->add(state, one));

    TS_ASSERT_EQUALS(Fixnum::from(2), two);
    TS_ASSERT_EQUALS(2, two->to_native());
  }
Esempio n. 7
0
  void test_sub() {
    Fixnum* one = Fixnum::from(1);
    Fixnum* zero = as<Fixnum>(one->sub(state, one));

    TS_ASSERT_EQUALS(0, zero->to_native());
    TS_ASSERT_EQUALS(Fixnum::from(0), zero);
  }
Esempio n. 8
0
  String* MatchData::post_matched(STATE) {
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    native_int f = fin->to_native();
    native_int max = source_->byte_size();

    String* string;

    if(!fin || f >= max) {
      string = String::create(state, 0, 0);
    } else {
      const char* str = (char*)source_->byte_address();
      native_int sz = max - f;

      if(sz > max) sz = max;

      string = String::create(state, str + f, sz);
    }

    source_->infect(state, string);
    string->encoding_from(state, source_);
    string->klass(state, source_->class_object(state));

    return string;
  }
Esempio n. 9
0
  Object* PackedObject::packed_ivar_delete(STATE, Symbol* sym, bool* removed) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return del_table_ivar(state, sym, removed);
    }

    if(removed) *removed = true;

    Object* val = body_as_array()[which->to_native()];
    body_as_array()[which->to_native()] = Qundef;

    return val;
  }
Esempio n. 10
0
  String* MatchData::matched_string(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    native_int max = source_->size();
    native_int f = fin->to_native();
    native_int b = beg->to_native();

    if(!beg || !fin ||
        f > max || b > max || b < 0) {
      return String::create(state, 0, 0);
    }

    const char* str = (char*)source_->byte_address();
    native_int sz = fin->to_native() - beg->to_native();

    return String::create(state, str + beg->to_native(), sz);
  }
Esempio n. 11
0
  void test_div() {
    Fixnum* one = as<Fixnum>(Fixnum::from(4));

    Fixnum* two = as<Fixnum>(one->div(state, one));
    TS_ASSERT_EQUALS(two->to_native(), 1);

    Fixnum* zero = Fixnum::from(0);
    TS_ASSERT_THROWS_ASSERT(one->div(state, zero), const RubyException &e,
                            TS_ASSERT(Exception::zero_division_error_p(state, e.exception)));
  }
Esempio n. 12
0
 /** @todo Is it a valid assumption that the position always increases? */
 void test_control_tells_current_position() {
   char *dir = make_directory();
   String* path = String::create(state, dir);
   d->open(state, path);
   Fixnum* pos = (Fixnum*)d->control(state, Fixnum::from(2), Fixnum::from(0));
   d->read(state);
   Fixnum* pos2 = (Fixnum*)d->control(state, Fixnum::from(2), Fixnum::from(0));
   TS_ASSERT_LESS_THAN(pos->to_native(), pos2->to_native());
   remove_directory(dir);
 }
Esempio n. 13
0
  Object* MatchData::nth_capture(STATE, native_int which) {
    if(region_->num_fields() <= which) return Qnil;

    Tuple* sub = try_as<Tuple>(region_->at(state, which));
    if(!sub) return Qnil;

    Fixnum* beg = try_as<Fixnum>(sub->at(state, 0));
    Fixnum* fin = try_as<Fixnum>(sub->at(state, 1));

    if(!beg || !fin ||
        fin->to_native() > source_->size() ||
        beg->to_native() < 0) {
      return Qnil;
    }

    const char* str = source_->c_str();
    native_int sz = fin->to_native() - beg->to_native();

    return String::create(state, str + beg->to_native(), sz);
  }
Esempio n. 14
0
  Object* PackedObject::get_packed_ivar(STATE, Symbol* sym) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    assert(tbl && !tbl->nil_p());

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym));
    if(!which) {
      return get_table_ivar(state, sym);
    }

    Object* obj = body_as_array()[which->to_native()];
    if(obj == Qundef) return Qnil;
    return obj;
  }
Esempio n. 15
0
    virtual Object* immediate() {
      native_int id = id_->to_native();

      if(id & TAG_REF_MASK) {
        Object* obj = reinterpret_cast<Object*>(id);

        // Be sure to not leak a bad reference leak out here.
        if(obj->reference_p()) return cNil;
        return obj;
      }

      return 0;
    }
Esempio n. 16
0
  Object* PackedObject::packed_ivar_defined(STATE, Symbol* sym) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return table_ivar_defined(state, sym);
    }

    Object* obj = body_as_array()[which->to_native()];
    if(obj == Qundef) return Qfalse;
    return Qtrue;
  }
Esempio n. 17
0
  Object* PackedObject::set_packed_ivar(STATE, Symbol* sym, Object* val) {
    LookupTable* tbl = this->reference_class()->packed_ivar_info();
    bool found = false;

    Fixnum* which = try_as<Fixnum>(tbl->fetch(state, sym, &found));
    if(!found) {
      return set_table_ivar(state, sym, val);
    }

    body_as_array()[which->to_native()] = val;
    if(val->reference_p()) write_barrier(state, val);
    return val;
  }
Esempio n. 18
0
  int Encoding::find_index(STATE, const char* name) {
    Object* obj = encoding_map(state)->fetch(state, encoding_symbol(state, name));

    if(Tuple* ref = try_as<Tuple>(obj)) {
      Fixnum* index = try_as<Fixnum>(ref->at(1));
      if(index) {
        return index->to_native();
      } else {
        return -1;
      }
    } else {
      return -1;
    }
  }
Esempio n. 19
0
  String* MatchData::pre_matched(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));

    native_int max = source_->size();
    native_int sz = beg->to_native();

    if(!beg || sz <= 0) {
      return String::create(state, 0, 0);
    }

    if(sz > max) sz = max;

    const char* str = (char*)source_->byte_address();

    return String::create(state, str, sz);
  }
Esempio n. 20
0
  String* MatchData::post_matched(STATE) {
    Fixnum* fin = try_as<Fixnum>(full_->at(state, 1));

    native_int f = fin->to_native();
    native_int max = source_->size();

    if(!fin || f >= max) {
      return String::create(state, 0, 0);
    }

    const char* str = (char*)source_->byte_address();
    native_int sz = max - f;

    if(sz > max) sz = max;

    return String::create(state, str + f, sz);
  }
Esempio n. 21
0
  String* MatchData::pre_matched(STATE) {
    Fixnum* beg = try_as<Fixnum>(full_->at(state, 0));

    native_int max = source_->byte_size();
    native_int sz = beg->to_native();

    String* string;

    if(!beg || sz <= 0) {
      string = String::create(state, 0, 0);
    } else {
      if(sz > max) sz = max;

      const char* str = (char*)source_->byte_address();

      string = String::create(state, str, sz);
    }

    source_->infect(state, string);
    string->encoding_from(state, source_);
    string->klass(state, source_->class_object(state));

    return string;
  }
Esempio n. 22
0
  bool BytecodeVerification::verify_from(STATE, int sp, int ip,
                                         std::list<Section>& ips)
  {
    if(sp < 0) {
      fail("internal error", ip);
      return false;
    }

    for(;;) {
      int old_sp = stack_[ip];
      if(old_sp < 0) {
        stack_[ip] = sp;
      } else if(old_sp != sp) {
        fail("inconsistent stack depth", ip);
        return false;
      } else {
        // Already been here and stack is consistent, done.
        return true;
      }

      Fixnum* obj = try_as<Fixnum>(ops_->at(ip++));
      if(!obj) {
        fail("corrupt instruction sequence", ip);
        return false;
      }

      opcode op = obj->to_native();
      size_t width = InstructionSequence::instruction_width(op);

      opcode arg1 = 0;
      opcode arg2 = 0;

      switch(width) {
      case 1:
        // nothing, done.
        break;
      case 2:
        if(ip >= total_) {
          fail("truncated instruction sequence", ip);
          return false;
        }

        obj = try_as<Fixnum>(ops_->at(ip++));
        if(!obj) {
          fail("corrupt instruction sequence", ip);
          return false;
        }
        arg1 = obj->to_native();
        break;

      case 3:
        if(ip >= total_) {
          fail("truncated instruction sequence", ip);
          return false;
        }

        obj = try_as<Fixnum>(ops_->at(ip++));
        if(!obj) {
          fail("corrupt instruction sequence", ip);
          return false;
        }

        arg1 = obj->to_native();

        if(ip >= total_) {
          fail("truncated instruction sequence", ip);
          return false;
        }

        obj = try_as<Fixnum>(ops_->at(ip++));
        if(!obj) {
          fail("corrupt instruction sequence", ip);
          return false;
        }

        arg2 = obj->to_native();
        break;

      default:
        fail("invalid instruction", ip);
        return false;
      }

      int read=0, write=0;

      int effect = stack_difference(op, arg1, arg2, &read, &write);

      // Check for under read
      if(sp - read < 0) {
        fail("stack underflow on read", ip);
        return false;
      }

      // Apply the total effect to propagate it.
      sp += effect;
      if(sp < 0) {
        fail("stack underflow on effect", ip);
        return false;
      }

      // Make sure we don't use more than the declared stack size.
      if(sp > max_stack_allowed_) {
        fail("stack overflow", ip);
        return false;
      }

      // Keep track of the max stack depth seen
      if(sp > max_stack_seen_) max_stack_seen_ = sp;

      switch(op) {
      case InstructionSequence::insn_push_local:
      case InstructionSequence::insn_set_local:
        if((native_int)arg1 < 0 || (native_int)arg1 >= locals_) {
          fail("invalid local variable access", ip);
          return false;
        }
        break;
      case InstructionSequence::insn_goto:
        if((native_int)arg1 < 0 || (native_int)arg1 >= total_) {
          fail("invalid goto location", ip);
          return false;
        }

        // Only handle forward branches.
        if((int)arg1 > ip) {
          ip = (int)arg1;
        } else {
          return true;
        }
        break;
      case InstructionSequence::insn_push_stack_local:
      case InstructionSequence::insn_set_stack_local:
        if((int)arg1 > max_stack_local_) {
          max_stack_local_ = (int)arg1;
        }
        break;
      case InstructionSequence::insn_goto_if_false:
      case InstructionSequence::insn_goto_if_true:
      case InstructionSequence::insn_setup_unwind:
        if((native_int)arg1 < 0 || (native_int)arg1 >= total_) {
          fail("invalid goto location", ip);
          return false;
        }

        if((int)arg1 > ip) {
          ips.push_back(Section(sp, arg1));
        }

        break;
      case InstructionSequence::insn_ret:
      case InstructionSequence::insn_raise_exc:
      case InstructionSequence::insn_raise_return:
      case InstructionSequence::insn_ensure_return:
      case InstructionSequence::insn_raise_break:
      case InstructionSequence::insn_reraise:
        return true;
      }

      // Detect falling off the end of the stream
      if(ip >= total_) {
        fail("unterminated instruction sequence", ip);
        return false;
      }
    }
  }
Esempio n. 23
0
  bool BytecodeVerification::verify(STATE) {
    // Do this setup here instead of the constructor so we can do
    // some validation of the CompiledCode's fields we read them.

    // Double check the method itself, since it might be a nil
    if(!kind_of<CompiledCode>(method_)) {
      fail("invalid method", -1);
      return false;
    }

    if(Fixnum* fix = try_as<Fixnum>(method_->local_count())) {
      locals_ = fix->to_native();
    } else {
      fail("method not initialized properly", -1);
      return false;
    }

    InstructionSequence* iseq = try_as<InstructionSequence>(method_->iseq());
    if(!iseq) {
      fail("method not initialized properly", -1);
      return false;
    }

    if(Tuple* tup = try_as<Tuple>(iseq->opcodes())) {
      ops_ = tup;
    } else {
      fail("method not initialized properly", -1);
      return false;
    }

    if(Fixnum* fix = try_as<Fixnum>(method_->stack_size())) {
      max_stack_allowed_ = fix->to_native();
    } else {
      fail("method not initialized properly", -1);
      return false;
    }

    if(Fixnum* fix = try_as<Fixnum>(method_->splat())) {
      if(fix->to_native() >= locals_) {
        fail("invalid splat position", -1);
        return false;
      }
    }

    Fixnum* tot = try_as<Fixnum>(method_->total_args());
    Fixnum* req = try_as<Fixnum>(method_->required_args());
    Fixnum* post = try_as<Fixnum>(method_->post_args());

    if(!tot || !req || !post) {
      fail("method not initialized properly (missing arg counts)", -1);
      return false;
    }

    if(tot->to_native() > locals_) {
      fail("more arguments than local slots", -1);
      return false;
    }

    if(req->to_native() > tot->to_native()) {
      fail("more required arguments than total", -1);
      return false;
    }

    if(post->to_native() > req->to_native()) {
      fail("more post arguments than required", -1);
      return false;
    }

    if(post->to_native() > tot->to_native()) {
      fail("more post arguments than total", -1);
      return false;
    }

    total_ = ops_->num_fields();
    stack_ = new int32_t[total_];

    for(native_int i = 0; i < total_; i++) {
      stack_[i] = -1;
    }

    std::list<Section> ips;
    ips.push_back(Section(0, 0));

    while(!ips.empty()) {
      Section& section = ips.front();

      int ip = section.ip;
      int sp = section.sp;

      ips.pop_front();

      if(!verify_from(state, sp, ip, ips)) return false;
    }

    // Now, check there is a enough space for the stack locals.
    if(max_stack_seen_ + max_stack_local_ >= max_stack_allowed_) {
      fail("not enough space for stack locals", -1);
      return false;
    }

    return true;
  }
Esempio n. 24
0
Integer* Integer::from_cstr(STATE, const char* str, const char* end,
                            int base, Object* strict) {

    bool negative = false;

    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(CBOOL(strict)) {
                return nil<Integer>();
            } else {
                return Fixnum::from(0);
            }
        }

        str++;
    }

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

    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(*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 fits = true;
    Fixnum* small = from_cstr_fixnum(state, &str, end, negative, base, strict, &fits);
    if(fits) return small;
    return from_cstr_bignum(state, str, end, small->to_native(), negative, base, strict);
}
Esempio n. 25
0
  void test_mod() {
    Fixnum* one = as<Fixnum>(Fixnum::from(4));

    Fixnum* two = as<Fixnum>(one->mod(state, one));
    TS_ASSERT_EQUALS(two->to_native(), 0);
  }