void test_get_breakpoint_flags() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("@blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 3); iseq->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_push_ivar)); iseq->opcodes()->put(state, 1, Fixnum::from(0)); iseq->opcodes()->put(state, 2, Fixnum::from(4 << 24 | InstructionSequence::insn_push_nil)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 0), 0U); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 2), (4U << 24)); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 1), 0U); }
InstructionSequence* UnMarshaller::get_iseq() { size_t count; char data[OPCODE_LENGTH]; stream >> count; // Read off newline stream.get(); InstructionSequence* iseq = InstructionSequence::create(state, count); Tuple* ops = iseq->opcodes(); for(size_t i = 0; i < count; i++) { stream.getline(data, OPCODE_LENGTH); long op = strtol(data, NULL, 10); ops->put(state, i, Fixnum::from(op)); } iseq->post_marshal(state); return iseq; }
InstructionSequence* InstructionSequence::create(STATE, size_t instructions) { InstructionSequence* is = state->new_object<InstructionSequence>(G(iseq)); is->opcodes(state, Tuple::create(state, instructions)); return is; }
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; }