[macruby-changes] [3169] MacRuby/branches/ticket159
source_changes at macosforge.org
source_changes at macosforge.org
Wed Dec 23 15:59:59 PST 2009
Revision: 3169
http://trac.macosforge.org/projects/ruby/changeset/3169
Author: emoy at apple.com
Date: 2009-12-23 15:59:56 -0800 (Wed, 23 Dec 2009)
Log Message:
-----------
Branch ticket159: fixed crasher, improved optimization, uniqued literals, added
IR debugging mode that gives descriptive names to variables, added strict mode,
fixed rubyc temp file clashes
Modified Paths:
--------------
MacRuby/branches/ticket159/array.c
MacRuby/branches/ticket159/bignum.c
MacRuby/branches/ticket159/bin/rubyc
MacRuby/branches/ticket159/compiler.cpp
MacRuby/branches/ticket159/compiler.h
MacRuby/branches/ticket159/include/ruby/intern.h
MacRuby/branches/ticket159/include/ruby/ruby.h
MacRuby/branches/ticket159/io.c
MacRuby/branches/ticket159/marshal.c
MacRuby/branches/ticket159/numeric.c
MacRuby/branches/ticket159/object.c
MacRuby/branches/ticket159/ruby.c
MacRuby/branches/ticket159/sprintf.c
MacRuby/branches/ticket159/vm.cpp
Modified: MacRuby/branches/ticket159/array.c
===================================================================
--- MacRuby/branches/ticket159/array.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/array.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -1923,7 +1923,7 @@
}
return 0;
}
- else if (TYPE(a) == T_FLOAT && TYPE(b) == T_FLOAT) {
+ else if (FLOAT_P(a) && FLOAT_P(b)) {
const double fa = RFLOAT_VALUE(a);
const double fb = RFLOAT_VALUE(b);
if (fa > fb) {
@@ -2935,8 +2935,8 @@
VALUE item1 = rary_elt(RARY(ary1), i);
VALUE item2 = rary_elt(RARY(ary2), i);
- if ((TYPE(item1) == T_FLOAT && isnan(RFLOAT_VALUE(item1)))
- || TYPE(item2) == T_FLOAT && isnan(RFLOAT_VALUE(item2))) {
+ if ((FLOAT_P(item1) && isnan(RFLOAT_VALUE(item1)))
+ || FLOAT_P(item2) && isnan(RFLOAT_VALUE(item2))) {
return Qfalse;
}
Modified: MacRuby/branches/ticket159/bignum.c
===================================================================
--- MacRuby/branches/ticket159/bignum.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/bignum.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -2235,8 +2235,9 @@
static VALUE
bit_coerce(VALUE x)
{
- while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
- if (TYPE(x) == T_FLOAT) {
+ int t;
+ while (!FIXNUM_P(x) && (t = TYPE(x)) != T_BIGNUM) {
+ if (t == T_FLOAT) {
rb_raise(rb_eTypeError, "can't convert Float into Integer");
}
x = rb_to_int(x);
Modified: MacRuby/branches/ticket159/bin/rubyc
===================================================================
--- MacRuby/branches/ticket159/bin/rubyc 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/bin/rubyc 2009-12-23 23:59:56 UTC (rev 3169)
@@ -267,7 +267,7 @@
end
def gen_tmpfile(base, ext)
- file = File.join(@tmpdir, "#{base}.#{ext}")
+ file = File.join(@tmpdir, "#{base}-#{$$}.#{ext}")
@tmpfiles << file
file
end
Modified: MacRuby/branches/ticket159/compiler.cpp
===================================================================
--- MacRuby/branches/ticket159/compiler.cpp 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/compiler.cpp 2009-12-23 23:59:56 UTC (rev 3169)
@@ -133,6 +133,10 @@
setScopeFunc = NULL;
setCurrentClassFunc = NULL;
getCacheFunc = NULL;
+ floatValueFunc = NULL;
+ newFloatFunc = NULL;
+ effectiveImmediateBitsFunc = NULL;
+ zeroDivFunc = NULL;
VoidTy = Type::getVoidTy(context);
Int1Ty = Type::getInt1Ty(context);
@@ -199,11 +203,62 @@
inline bool
RoxorCompiler::unbox_ruby_constant(Value *val, VALUE *rval)
{
- if (ConstantInt::classof(val)) {
- long tmp = cast<ConstantInt>(val)->getZExtValue();
- *rval = tmp;
- return true;
+ {
+ /* Unbox a direct ConstantInt value */
+ ConstantInt *const_int = dyn_cast<ConstantInt>(val);
+ if (const_int != NULL) {
+ long tmp = const_int->getZExtValue();
+ *rval = tmp;
+ return true;
+ }
}
+
+ if (newFloatFunc == NULL) {
+ // VALUE rb_float_new_retained(double)
+ newFloatFunc = cast<Function>
+ (module->getOrInsertFunction("rb_float_new_retained",
+ RubyObjTy, DoubleTy, NULL));
+ }
+
+ {
+ /*
+ * Unbox a CallInst to newFloatFunc (a literal floating point value)
+ * by getting the ConstantFP argument to the call.
+ */
+ CallInst *callinst = dyn_cast<CallInst>(val);
+ ConstantFP *const_fp;
+ if (callinst != NULL
+ && callinst->getCalledFunction() == newFloatFunc
+ && (const_fp = dyn_cast<ConstantFP>(callinst->getOperand(1)))
+ != NULL)
+ {
+ *rval = rb_float_new(const_fp->getValueAPF().convertToDouble());
+ return true;
+ }
+ }
+
+ {
+ /*
+ * Unbox a LoadInst of a GlobalVariable. We have previously stored
+ * the value of the GlobalVariable in the std::map named global_values
+ * (since the AOT compiler doesn't initialize the GlobalVariable with
+ * the true value until later).
+ */
+ GlobalVariable *gvar;
+ LoadInst *load_inst = dyn_cast<LoadInst>(val);
+ if (load_inst != NULL
+ && (gvar = dyn_cast<GlobalVariable>(load_inst->getOperand(0)))
+ != NULL)
+ {
+ std::map<GlobalVariable *, VALUE>::iterator iter
+ = global_values.find(gvar);
+ if (iter != global_values.end()) {
+ *rval = iter->second;
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -215,13 +270,22 @@
}
Instruction *
+#ifdef DEBUG_IR
+RoxorCompiler::compile_protected_call(Value *imp, std::vector<Value *> ¶ms,
+ std::string *name)
+#else /* !DEBUG_IR */
RoxorCompiler::compile_protected_call(Value *imp, std::vector<Value *> ¶ms)
+#endif /* DEBUG_IR */
{
if (rescue_invoke_bb == NULL) {
CallInst *dispatch = CallInst::Create(imp,
params.begin(),
params.end(),
+#ifdef DEBUG_IR
+ name ? *name : "",
+#else /* !DEBUG_IR */
"",
+#endif /* DEBUG_IR */
bb);
return dispatch;
}
@@ -234,7 +298,11 @@
rescue_invoke_bb,
params.begin(),
params.end(),
+#ifdef DEBUG_IR
+ name ? *name : "",
+#else /* !DEBUG_IR */
"",
+#endif /* DEBUG_IR */
bb);
bb = normal_bb;
@@ -480,7 +548,11 @@
std::vector<Value *> params;
params.push_back(compile_mcache(selEqq, false));
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(selEqq, true);
+#ifdef DEBUG_IR
+ params.push_back(new LoadInst(is_redefined, "[is_redefined:===:]", bb));
+#else /* !DEBUG_IR */
params.push_back(new LoadInst(is_redefined, "", bb));
+#endif /* DEBUG_IR */
params.push_back(comparedToVal);
params.push_back(splatVal);
@@ -566,7 +638,8 @@
params.push_back(sel);
params.push_back(ConstantInt::get(Int8Ty, super ? 1 : 0));
- return CallInst::Create(getCacheFunc, params.begin(), params.end(), "", bb);
+ return CallInst::Create(getCacheFunc, params.begin(), params.end(),
+ "", bb);
}
Value *
@@ -626,7 +699,36 @@
return new LoadInst(gvar, "", bb);
}
+#ifdef DEBUG_IR
Value *
+RoxorCompiler::compile_sel(SEL sel, bool add_to_bb)
+{
+ std::string name("[sel:");
+ name.append(sel_getName(sel));
+ name.push_back(']');
+
+ std::map<std::string, GlobalVariable *>::iterator iter = globals.find(name);
+
+ GlobalVariable *gvar;
+ if (iter == globals.end()) {
+ gvar = new GlobalVariable(*RoxorCompiler::module, PtrTy, false,
+ GlobalValue::InternalLinkage,
+ compile_const_pointer((void *)sel), "");
+ assert(gvar != NULL);
+
+ globals[name] = gvar;
+ }
+ else {
+ gvar = iter->second;
+ }
+
+ return add_to_bb
+ ? new LoadInst(gvar, name, bb)
+ : new LoadInst(gvar, name);
+}
+#endif /* DEBUG_IR */
+
+Value *
RoxorAOTCompiler::compile_sel(SEL sel, bool add_to_bb)
{
std::map<SEL, GlobalVariable *>::iterator iter = sels.find(sel);
@@ -641,9 +743,18 @@
else {
gvar = iter->second;
}
+#ifdef DEBUG_IR
+ std::string name("[sel:");
+ name.append(sel_getName(sel));
+ name.push_back(']');
return add_to_bb
+ ? new LoadInst(gvar, name, bb)
+ : new LoadInst(gvar, name);
+#else /* !DEBUG_IR */
+ return add_to_bb
? new LoadInst(gvar, "", bb)
: new LoadInst(gvar, "");
+#endif /* DEBUG_IR */
}
inline Value *
@@ -1145,7 +1256,15 @@
params.push_back(compile_id(vid));
params.push_back(compile_slot_cache(vid));
+#ifdef DEBUG_IR
+ std::string name("[ivar:");
+ name.append(rb_id2name(vid));
+ name.push_back(']');
+
+ return CallInst::Create(getIvarFunc, params.begin(), params.end(), name, bb);
+#else /* !DEBUG_IR */
return CallInst::Create(getIvarFunc, params.begin(), params.end(), "", bb);
+#endif /* DEBUG_IR */
}
Value *
@@ -1189,7 +1308,15 @@
params.push_back(ConstantInt::get(Int8Ty, check ? 1 : 0));
params.push_back(ConstantInt::get(Int8Ty, dynamic_class ? 1 : 0));
+#ifdef DEBUG_IR
+ std::string name("[cvar:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+
+ return compile_protected_call(cvarGetFunc, params, &name);
+#else /* !DEBUG_IR */
return compile_protected_call(cvarGetFunc, params);
+#endif /* DEBUG_IR */
}
Value *
@@ -1210,8 +1337,17 @@
params.push_back(val);
params.push_back(ConstantInt::get(Int8Ty, dynamic_class ? 1 : 0));
+#ifdef DEBUG_IR
+ std::string vname("[cvar:");
+ vname.append(rb_id2name(name));
+ vname.push_back(']');
+
return CallInst::Create(cvarSetFunc, params.begin(),
+ params.end(), vname, bb);
+#else /* !DEBUG_IR */
+ return CallInst::Create(cvarSetFunc, params.begin(),
params.end(), "", bb);
+#endif /* DEBUG_IR */
}
Value *
@@ -1229,7 +1365,15 @@
params.push_back(compile_global_entry(node));
params.push_back(val);
+#ifdef DEBUG_IR
+ std::string name("[gvar:");
+ name.append(rb_id2name(node->nd_vid));
+ name.push_back(']');
+
+ return compile_protected_call(gvarSetFunc, params, &name);
+#else /* !DEBUG_IR */
return compile_protected_call(gvarSetFunc, params);
+#endif /* DEBUG_IR */
}
Value *
@@ -1315,7 +1459,30 @@
inline Value *
RoxorCompiler::compile_id(ID id)
{
+#ifdef DEBUG_IR
+ std::string name("[id:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+
+ std::map<std::string, GlobalVariable *>::iterator iter = globals.find(name);
+
+ GlobalVariable *gvar;
+ if (iter == globals.end()) {
+ gvar = new GlobalVariable(*RoxorCompiler::module,
+ IntTy, false, GlobalValue::InternalLinkage,
+ ConstantInt::get(IntTy, (long)id), "");
+
+ globals[name] = gvar;
+ }
+ else {
+ gvar = iter->second;
+ }
+ return bb
+ ? new LoadInst(gvar, name, bb)
+ : new LoadInst(gvar, name);
+#else /* !DEBUG_IR */
return ConstantInt::get(IntTy, (long)id);
+#endif /* DEBUG_IR */
}
Value *
@@ -1333,7 +1500,14 @@
gvar = iter->second;
}
+#ifdef DEBUG_IR
+ std::string name("[id:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+ return new LoadInst(gvar, name, bb);
+#else /* !DEBUG_IR */
return new LoadInst(gvar, "", bb);
+#endif /* DEBUG_IR */
}
Value *
@@ -1362,7 +1536,15 @@
params.push_back(compile_id(id));
params.push_back(ConstantInt::get(Int8Ty, dynamic_class ? 1 : 0));
+#ifdef DEBUG_IR
+ std::string name("[const:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+
+ return compile_protected_call(getConstFunc, params, &name);
+#else /* !DEBUG_IR */
return compile_protected_call(getConstFunc, params);
+#endif /* DEBUG_IR */
}
Value *
@@ -1618,7 +1800,15 @@
Value *index = ConstantInt::get(Int32Ty, idx);
Value *slot = GetElementPtrInst::Create(dvars_ary, index, rb_id2name(name),
bb);
+#ifdef DEBUG_IR
+ std::string vname("[dvar:");
+ vname.append(rb_id2name(name));
+ vname.push_back(']');
+
+ return new LoadInst(slot, vname, bb);
+#else /* !DEBUG_IR */
return new LoadInst(slot, "", bb);
+#endif /* DEBUG_IR */
}
void
@@ -2017,7 +2207,7 @@
val->v.l = FIX2LONG(rval);
return true;
}
- else if (TYPE(rval) == T_FLOAT) {
+ else if (FLOAT_P(rval)) {
val->type = T_FLOAT;
val->v.d = RFLOAT_VALUE(rval);
return true;
@@ -2136,6 +2326,13 @@
RoxorCompiler::compile_double_coercion(Value *val, Value *mask,
BasicBlock *fallback_bb, Function *f)
{
+ if (floatValueFunc == NULL) {
+ // double rb_vm_float_value(VALUE)
+ floatValueFunc = cast<Function>
+ (module->getOrInsertFunction("rb_vm_float_value",
+ DoubleTy, RubyObjTy, NULL));
+ }
+
Value *is_float = new ICmpInst(*bb, ICmpInst::ICMP_EQ, mask, threeVal);
BasicBlock *is_float_bb = BasicBlock::Create(context, "is_float", f);
@@ -2145,13 +2342,10 @@
BranchInst::Create(is_float_bb, isnt_float_bb, is_float, bb);
bb = is_float_bb;
- Value *is_float_val = BinaryOperator::CreateXor(val, threeVal, "", bb);
-#if __LP64__
- is_float_val = new BitCastInst(is_float_val, DoubleTy, "", bb);
-#else
- is_float_val = new BitCastInst(is_float_val, FloatTy, "", bb);
- is_float_val = new FPExtInst(is_float_val, DoubleTy, "", bb);
-#endif
+ std::vector<Value *> params;
+ params.push_back(val);
+ Value *is_float_val = CallInst::Create(floatValueFunc, params.begin(),
+ params.end(), "", bb);
BranchInst::Create(merge_bb, bb);
bb = isnt_float_bb;
@@ -2215,6 +2409,11 @@
}
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
+#ifdef DEBUG_IR
+ std::string name("[is_redefined:");
+ name.append(sel_getName(sel));
+ name.push_back(']');
+#endif /* DEBUG_IR */
Value *leftVal = params[2]; // self
Value *rightVal = params.back();
@@ -2227,7 +2426,11 @@
&& TYPE(leftRVal) == T_SYMBOL && TYPE(rightRVal) == T_SYMBOL) {
// Both operands are symbol constants.
if (sel == selEq || sel == selEqq || sel == selNeq) {
+#ifdef DEBUG_IR
+ Value *is_redefined_val = new LoadInst(is_redefined, name, bb);
+#else /* !DEBUG_IR */
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
+#endif /* DEBUG_IR */
Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(context));
@@ -2267,6 +2470,13 @@
}
}
+ if (newFloatFunc == NULL) {
+ // VALUE rb_float_new_retained(double)
+ newFloatFunc = cast<Function>
+ (module->getOrInsertFunction("rb_float_new_retained",
+ RubyObjTy, DoubleTy, NULL));
+ }
+
rb_vm_immediate_val_t leftImm, rightImm;
const bool leftIsImmediateConst = unbox_immediate_val(leftRVal,
&leftImm);
@@ -2289,7 +2499,7 @@
res_val = res == 1 ? trueVal : falseVal;
}
else if (FIXABLE(res)) {
- res_val = ConstantInt::get(RubyObjTy, LONG2FIX(res));
+ res_val = compile_immutable_literal(LONG2FIX(res));
}
}
}
@@ -2306,14 +2516,17 @@
res_val = res == 1 ? trueVal : falseVal;
}
else {
- res_val = ConstantInt::get(RubyObjTy,
- DOUBLE2NUM(res));
+ res_val = compile_immutable_literal(DOUBLE2NUM(res));
}
}
}
if (res_val != NULL) {
+#ifdef DEBUG_IR
+ Value *is_redefined_val = new LoadInst(is_redefined, name, bb);
+#else /* !DEBUG_IR */
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
+#endif /* DEBUG_IR */
Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(context));
@@ -2343,11 +2556,21 @@
return NULL;
}
else {
+ if (effectiveImmediateBitsFunc == NULL) {
+ // int rb_vm_effective_immediate_bits(VALUE)
+ effectiveImmediateBitsFunc = cast<Function>
+ (module->getOrInsertFunction("rb_vm_effective_immediate_bits",
+ IntTy, RubyObjTy, NULL));
+ }
+
// Either one or both is not a constant immediate.
+#ifdef DEBUG_IR
+ Value *is_redefined_val = new LoadInst(is_redefined, name, bb);
+#else /* !DEBUG_IR */
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
+#endif /* DEBUG_IR */
Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(context));
-
Function *f = bb->getParent();
BasicBlock *not_redefined_bb =
@@ -2363,18 +2586,57 @@
BranchInst::Create(not_redefined_bb, dispatch_bb, isOpRedefined,
bb);
+ BasicBlock *div_by_zero_bb;
+ BasicBlock *optimize_fixnum_cont_bb;
+ BasicBlock *optimize_fixnum_ret_bb;
+ /*
+ * In the case of integer division, we need to test for the
+ * divisor being zero, and throw an exception if so. Because
+ * the BasicBlock from which the final fixnum varies depending
+ * on whether we are dealing with division, whether the result
+ * is a predicate or other cases, we use the optimize_fixnum_ret_bb
+ * variable to record that final BasicBlock, which we use to setup
+ * the PHINode (this make the code easier to decipher).
+ */
+ bool doDIV = (sel == selDIV);
+ if (doDIV) {
+ div_by_zero_bb =
+ BasicBlock::Create(context, "div_by_zero", f);
+ optimize_fixnum_ret_bb = optimize_fixnum_cont_bb =
+ BasicBlock::Create(context, "op_optimize_fixnum_cont", f);
+
+ if (zeroDivFunc == NULL) {
+ // void rb_num_zerodiv(void)
+ zeroDivFunc = cast<Function>
+ (module->getOrInsertFunction("rb_num_zerodiv",
+ VoidTy, NULL));
+ zeroDivFunc->setDoesNotReturn(true);
+ }
+
+ bb = div_by_zero_bb;
+ CallInst::Create(zeroDivFunc, "", bb);
+ new UnreachableInst(context, bb);
+ }
+ else {
+ optimize_fixnum_ret_bb = optimize_fixnum_bb;
+ }
+
bb = not_redefined_bb;
Value *leftAndOp = NULL;
if (!leftIsImmediateConst) {
- leftAndOp = BinaryOperator::CreateAnd(leftVal, threeVal, "",
- bb);
+ std::vector<Value *> params;
+ params.push_back(leftVal);
+ leftAndOp = CallInst::Create(effectiveImmediateBitsFunc,
+ params.begin(), params.end(), "", bb);
}
Value *rightAndOp = NULL;
if (!rightIsImmediateConst) {
- rightAndOp = BinaryOperator::CreateAnd(rightVal, threeVal, "",
- bb);
+ std::vector<Value *> params;
+ params.push_back(rightVal);
+ rightAndOp = CallInst::Create(effectiveImmediateBitsFunc,
+ params.begin(), params.end(), "", bb);
}
if (leftAndOp != NULL && rightAndOp != NULL) {
@@ -2416,21 +2678,29 @@
bb = optimize_fixnum_bb;
- Value *unboxedLeft;
- if (leftIsImmediateConst) {
- unboxedLeft = ConstantInt::get(IntTy, leftImm.long_val());
+ Value *unboxedRight;
+ if (rightIsImmediateConst) {
+ unboxedRight = ConstantInt::get(IntTy, rightImm.long_val());
}
else {
- unboxedLeft = BinaryOperator::CreateAShr(leftVal, twoVal, "",
+ unboxedRight = BinaryOperator::CreateAShr(rightVal, twoVal, "",
bb);
}
- Value *unboxedRight;
- if (rightIsImmediateConst) {
- unboxedRight = ConstantInt::get(IntTy, rightImm.long_val());
+ if (doDIV) {
+ Value *rightFixnumIsZero = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
+ unboxedRight, zeroVal);
+ BranchInst::Create(div_by_zero_bb, optimize_fixnum_cont_bb,
+ rightFixnumIsZero, bb);
+ bb = optimize_fixnum_cont_bb;
}
+
+ Value *unboxedLeft;
+ if (leftIsImmediateConst) {
+ unboxedLeft = ConstantInt::get(IntTy, leftImm.long_val());
+ }
else {
- unboxedRight = BinaryOperator::CreateAShr(rightVal, twoVal, "",
+ unboxedLeft = BinaryOperator::CreateAShr(leftVal, twoVal, "",
bb);
}
@@ -2463,7 +2733,7 @@
BranchInst::Create(merge_bb, dispatch_bb, isFixnumMinOk, bb);
fix_op_res = boxed_op_res;
- optimize_fixnum_bb = fixable_max_bb;
+ optimize_fixnum_ret_bb = fixable_max_bb;
}
else {
BranchInst::Create(merge_bb, bb);
@@ -2493,12 +2763,10 @@
if (!result_is_predicate) {
// Box the float.
-#if !__LP64__
- flp_op_res = new FPTruncInst(flp_op_res, FloatTy, "", bb);
-#endif
- flp_op_res = new BitCastInst(flp_op_res, RubyObjTy, "", bb);
- flp_op_res = BinaryOperator::CreateOr(flp_op_res, threeVal,
- "", bb);
+ std::vector<Value *> params;
+ params.push_back(flp_op_res);
+ flp_op_res = CallInst::Create(newFloatFunc, params.begin(),
+ params.end(), "", bb);
}
optimize_float_bb = bb;
BranchInst::Create(merge_bb, bb);
@@ -2513,7 +2781,7 @@
bb = merge_bb;
PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", bb);
- pn->addIncoming(fix_op_res, optimize_fixnum_bb);
+ pn->addIncoming(fix_op_res, optimize_fixnum_ret_bb);
pn->addIncoming(flp_op_res, optimize_float_bb);
pn->addIncoming(dispatch_val, dispatch_bb);
@@ -2568,7 +2836,14 @@
new_params.push_back(params[0]); // cache
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
+#ifdef DEBUG_IR
+ std::string name("[is_redefined:");
+ name.append(sel_getName(sel));
+ name.push_back(']');
+ new_params.push_back(new LoadInst(is_redefined, name, bb));
+#else /* !DEBUG_IR */
new_params.push_back(new LoadInst(is_redefined, "", bb));
+#endif /* DEBUG_IR */
return compile_protected_call(opt_func, new_params);
}
@@ -2590,7 +2865,14 @@
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
+#ifdef DEBUG_IR
+ std::string name("[is_redefined:");
+ name.append(sel_getName(sel));
+ name.push_back(']');
+ Value *is_redefined_val = new LoadInst(is_redefined, name, bb);
+#else /* !DEBUG_IR */
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
+#endif /* DEBUG_IR */
Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
is_redefined_val, ConstantInt::getFalse(context));
@@ -2787,7 +3069,11 @@
module->getOrInsertFunction(
"rb_str_new_empty", RubyObjTy, NULL));
}
+#ifdef DEBUG_IR
+ return CallInst::Create(newString3Func, "[str:]", bb);
+#else /* !DEBUG_IR */
return CallInst::Create(newString3Func, "", bb);
+#endif /* DEBUG_IR */
}
else {
UniChar *buf = (UniChar *)CFStringGetCharactersPtr(
@@ -2820,8 +3106,16 @@
params.push_back(load);
params.push_back(ConstantInt::get(Int32Ty, str_len));
+#ifdef DEBUG_IR
+ std::string name("[str:");
+ name.append(RSTRING_PTR(val));
+ name.push_back(']');
return CallInst::Create(newString2Func, params.begin(),
+ params.end(), name, bb);
+#else /* DEBUG_IR */
+ return CallInst::Create(newString2Func, params.begin(),
params.end(), "", bb);
+#endif /* DEBUG_IR */
}
}
@@ -2831,7 +3125,162 @@
Value *
RoxorCompiler::compile_immutable_literal(VALUE val)
{
+#ifdef DEBUG_IR
+ char buf[32]; // big enough for a double converted with %a and a FIXNUM
+
+ std::string name("[");
+
+ const int type = TYPE(val);
+ switch (type) {
+ case T_FALSE:
+ name.append("false");
+ break;
+
+ case T_NIL:
+ name.append("nil");
+ break;
+
+ case T_TRUE:
+ name.append("true");
+ break;
+
+ case T_UNDEF:
+ name.append("undef");
+ break;
+
+ case T_CLASS:
+ // This strange literal seems to be only emitted for
+ // `for' loops.
+ name.append("class:");
+ name.append(class_getName((Class)val));
+ break;
+
+ case T_MODULE:
+ name.append("module:");
+ name.append(class_getName((Class)val));
+ break;
+
+ case T_REGEXP:
+ name.append("re:");
+ name.append(RSTRING_PTR(rb_inspect(val)));
+ break;
+
+ case T_SYMBOL:
+ name.append("symbol:");
+ name.append(rb_id2name(SYM2ID(val)));
+ break;
+
+ case T_FIXNUM:
+ name.append("fixnum:");
+ snprintf(buf, sizeof(buf), "%ld", FIX2LONG(val));
+ name.append(buf);
+ break;
+
+ case T_BIGNUM:
+ name.append("bignum:");
+ name.append(RSTRING_PTR(rb_big2str(val, 10)));
+ break;
+
+ case T_FLOAT:
+ name.append("float:");
+ snprintf(buf, sizeof(buf), "%a", RFLOAT_VALUE(val));
+ name.append(buf);
+ break;
+
+ default:
+ if (rb_obj_is_kind_of(val, rb_cRange)) {
+ VALUE beg = 0, end = 0;
+ bool exclude_end = false;
+ rb_range_extract(val, &beg, &end, &exclude_end);
+
+ // For literal ranges, beg and end are FIXNUMs
+ assert(FIXNUM_P(beg) && FIXNUM_P(end));
+ name.append("range:");
+ snprintf(buf, sizeof(buf), "%ld", FIX2LONG(beg));
+ name.append(buf);
+ name.append(exclude_end ? "..." : "..");
+ snprintf(buf, sizeof(buf), "%ld", FIX2LONG(end));
+ name.append(buf);
+ }
+ else if (rb_obj_is_kind_of(val, rb_cEncoding)) {
+ name.append("enc:");
+ name.append(RSTRING_PTR(rb_enc_name2(
+ (CFStringEncoding *)DATA_PTR(val))));
+ }
+ else {
+ printf("unrecognized literal `%s' (class `%s' type %d)\n",
+ RSTRING_PTR(rb_inspect(val)),
+ rb_obj_classname(val),
+ TYPE(val));
+ abort();
+ }
+ break;
+ }
+ name.push_back(']');
+
+ std::map<std::string, GlobalVariable *>::iterator iter = globals.find(name);
+
+ GlobalVariable *gvar;
+ if (iter == globals.end()) {
+ GC_RETAIN(val); // make sure this doesn't get garbage collected
+ gvar = new GlobalVariable(*RoxorCompiler::module,
+ RubyObjTy, false, GlobalValue::InternalLinkage,
+ ConstantInt::get(RubyObjTy, (long)val), "");
+
+ globals[name] = gvar;
+ switch (type) {
+ case T_FIXNUM:
+ case T_FLOAT:
+ global_values[gvar] = val;
+ break;
+ }
+ }
+ else {
+ gvar = iter->second;
+ }
+ return new LoadInst(gvar, name, bb);
+#else /* !DEBUG_IR */
+#ifdef NOT_DEFINED_DUE_TO_LLVM_BUG_5026
+ /*
+ * The following code causes an abort with llvm-82747:
+ *
+ * Don't know how to fold this instruction!
+ * UNREACHABLE executed at .../lib/Target/X86/X86InstrInfo.cpp:2313!
+ * Stack dump:
+ * 0. Running pass 'Linear Scan Register Allocator' on function '@__ruby_scope1179'
+ *
+ * when running the core/float spec tests:
+ *
+ * ./mspec/bin/mspec ci -B ./spec/macruby.mspec ./spec/frozen/core/float
+ *
+ * This is bug #5026, and is fixed in llvm-83656. Using TOT llvm does
+ * not have this problem, but that has other problems.
+ */
+ if (FLOAT_P(val) && !FIXFLOAT_P(val)) {
+ if (newFloatFunc == NULL) {
+ // VALUE rb_float_new_retained(double)
+ newFloatFunc = cast<Function>
+ (module->getOrInsertFunction("rb_float_new_retained",
+ RubyObjTy, DoubleTy, NULL));
+ }
+
+ Value *d = ConstantFP::get(DoubleTy, RFLOAT_VALUE(val));
+
+ std::vector<Value *> params;
+ params.push_back(d);
+
+ return CallInst::Create(newFloatFunc,
+ params.begin(), params.end(), "", bb);
+ }
+#else /* !NOT_DEFINED_DUE_TO_LLVM_BUG_5026 */
+ /*
+ * So to avoid crashes due to GC releasing a float literal, we now
+ * retain the float before converting to a ConstantInt.
+ */
+ if (FLOAT_P(val)) GC_RETAIN(val);
+#endif /* NOT_DEFINED_DUE_TO_LLVM_BUG_5026 */
return ConstantInt::get(RubyObjTy, (long)val);
+#endif /* DEBUG_IR */
}
Value *
@@ -2846,19 +3295,104 @@
return nilVal;
}
- std::map<VALUE, GlobalVariable *>::iterator iter = literals.find(val);
+ /*
+ * We convert val to a string representation, so we can unique them, and
+ * avoid multiple GlobalVariable's of the same value. The string value
+ * is prefixed with a type, so that each type has its own effective
+ * namespace. When DEBUG_IR is defined, we also enclose the string in
+ * square brackets, and use it to name LLVM IR variables.
+ */
+ char buf[32]; // big enough for a double converted with %a and a FIXNUM
+#ifdef DEBUG_IR
+ std::string key("[");
+#else /* !DEBUG_IR */
+ std::string key;
+#endif /* DEBUG_IR */
+
+ const int type = TYPE(val);
+ switch (type) {
+ case T_CLASS:
+ // This strange literal seems to be only emitted for
+ // `for' loops.
+ key.append("class:");
+ key.append(class_getName((Class)val));
+ break;
+
+ case T_REGEXP:
+ {
+ struct RRegexp *re = (struct RRegexp *)val;
+
+ key.append("re:");
+ if (re->len > 0) key.append(RSTRING_PTR(rb_inspect(val)));
+ }
+ break;
+
+ case T_SYMBOL:
+ key.append("symbol:");
+ key.append(rb_id2name(SYM2ID(val)));
+ break;
+
+ case T_BIGNUM:
+ key.append("bignum:");
+ key.append(RSTRING_PTR(rb_big2str(val, 10)));
+ break;
+
+ case T_FLOAT:
+ key.append("float:");
+ snprintf(buf, sizeof(buf), "%a", RFLOAT_VALUE(val));
+ key.append(buf);
+ break;
+
+ default:
+ if (rb_obj_is_kind_of(val, rb_cRange)) {
+ VALUE beg = 0, end = 0;
+ bool exclude_end = false;
+ rb_range_extract(val, &beg, &end, &exclude_end);
+
+ // For literal ranges, beg and end are FIXNUMs
+ assert(FIXNUM_P(beg) && FIXNUM_P(end));
+ key.append("range:");
+ snprintf(buf, sizeof(buf), "%ld", FIX2LONG(beg));
+ key.append(buf);
+ key.append(exclude_end ? "..." : "..");
+ snprintf(buf, sizeof(buf), "%ld", FIX2LONG(end));
+ key.append(buf);
+ }
+ else {
+ printf("unrecognized literal `%s' (class `%s' type %d)\n",
+ RSTRING_PTR(rb_inspect(val)),
+ rb_obj_classname(val),
+ TYPE(val));
+ abort();
+ }
+ break;
+ }
+#ifdef DEBUG_IR
+ key.push_back(']');
+#endif /* DEBUG_IR */
+
+ std::map<std::string, std::pair<VALUE, GlobalVariable *> >::iterator iter
+ = literals.find(key);
GlobalVariable *gvar = NULL;
if (iter == literals.end()) {
gvar = new GlobalVariable(*RoxorCompiler::module, RubyObjTy, false,
GlobalValue::InternalLinkage, nilVal, "");
- literals[val] = gvar;
+ literals[key] = std::make_pair(val, gvar);
+
+ if (type == T_FLOAT) {
+ global_values[gvar] = val;
+ }
}
else {
- gvar = iter->second;
+ gvar = iter->second.second;
}
+#ifdef DEBUG_IR
+ return new LoadInst(gvar, key, bb);
+#else /* !DEBUG_IR */
return new LoadInst(gvar, "", bb);
+#endif /* DEBUG_IR */
}
Value *
@@ -2950,7 +3484,7 @@
Value *id_val = compile_id(ivar_name);
if (Instruction::classof(id_val)) {
Instruction *insn = cast<Instruction>(id_val);
- insn->removeFromParent();
+ if (bb) insn->removeFromParent();
list.insert(list_iter, insn);
}
params.push_back(id_val);
@@ -3167,7 +3701,14 @@
val = CallInst::Create(currentBlockObjectFunc, "", bb);
current_block_arg = val;
}
+#ifdef DEBUG_IR
+ std::string name("[arg:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+ Value *slot = new AllocaInst(RubyObjTy, name, bb);
+#else /* !DEBUG_IR */
Value *slot = new AllocaInst(RubyObjTy, "", bb);
+#endif /* DEBUG_IR */
new StoreInst(val, slot, bb);
lvars[id] = slot;
has_vars_to_save = true;
@@ -3371,7 +3912,15 @@
{
assert(node->nd_vid > 0);
+#ifdef DEBUG_IR
+ std::string name("[lval:");
+ name.append(rb_id2name(node->nd_vid));
+ name.push_back(']');
+
+ return new LoadInst(compile_lvar_slot(node->nd_vid), name, bb);
+#else /* !DEBUG_IR */
return new LoadInst(compile_lvar_slot(node->nd_vid), "", bb);
+#endif /* DEBUG_IR */
}
break;
@@ -3389,7 +3938,15 @@
params.push_back(compile_global_entry(node));
+#ifdef DEBUG_IR
+ std::string name("[gval:");
+ name.append(rb_id2name(node->nd_vid));
+ name.push_back(']');
+
+ return CallInst::Create(gvarGetFunc, params.begin(), params.end(), name, bb);
+#else /* !DEBUG_IR */
return CallInst::Create(gvarGetFunc, params.begin(), params.end(), "", bb);
+#endif /* DEBUG_IR */
}
break;
@@ -3950,7 +4507,14 @@
params.push_back(ConstantInt::get(Int8Ty,
outer && dynamic_class ? 1 : 0));
+#ifdef DEBUG_IR
+ std::string name("[class:");
+ name.append(rb_id2name(path));
+ name.push_back(']');
+ classVal = compile_protected_call(defineClassFunc, params, &name);
+#else /* !DEBUG_IR */
classVal = compile_protected_call(defineClassFunc, params);
+#endif /* DEBUG_IR */
}
NODE *body = node->nd_body;
@@ -4203,7 +4767,14 @@
// because if may have a default value.
ID argid = rb_intern(iter->getName().data());
Value *argslot = compile_lvar_slot(argid);
+#ifdef DEBUG_IR
+ std::string name("[lvar:");
+ name.append(iter->getName().data());
+ name.push_back(']');
+ params.push_back(new LoadInst(argslot, name, bb));
+#else /* !DEBUG_IR */
params.push_back(new LoadInst(argslot, "", bb));
+#endif /* DEBUG_IR */
++i;
++iter;
@@ -5446,20 +6017,24 @@
cast<Function>(module->getOrInsertFunction("rb_bignum_new_retained",
RubyObjTy, PtrTy, NULL));
- Function *newFloatFunc =
- cast<Function>(module->getOrInsertFunction("rb_float_from_astr_retained",
- RubyObjTy, PtrTy, NULL));
+ if (newFloatFunc == NULL) {
+ // VALUE rb_float_new_retained(double)
+ newFloatFunc = cast<Function>
+ (module->getOrInsertFunction("rb_float_new_retained",
+ RubyObjTy, DoubleTy, NULL));
+ }
Function *getClassFunc =
cast<Function>(module->getOrInsertFunction("objc_getClass",
RubyObjTy, PtrTy, NULL));
- for (std::map<VALUE, GlobalVariable *>::iterator i = literals.begin();
+ for (std::map<std::string, std::pair<VALUE, GlobalVariable *> >::iterator i
+ = literals.begin();
i != literals.end();
++i) {
- VALUE val = i->first;
- GlobalVariable *gvar = i->second;
+ VALUE val = i->second.first;
+ GlobalVariable *gvar = i->second.second;
switch (TYPE(val)) {
case T_CLASS:
@@ -5584,19 +6159,10 @@
case T_FLOAT:
{
- const char *astr = RSTRING_PTR(rb_float_to_astr(val));
+ Value *v = ConstantFP::get(DoubleTy, RFLOAT_VALUE(val));
- GlobalVariable *floatstr_gvar =
- compile_const_global_string(astr);
-
- std::vector<Value *> idxs;
- idxs.push_back(ConstantInt::get(Int32Ty, 0));
- idxs.push_back(ConstantInt::get(Int32Ty, 0));
- Instruction *load = GetElementPtrInst::Create(floatstr_gvar,
- idxs.begin(), idxs.end(), "");
-
std::vector<Value *> params;
- params.push_back(load);
+ params.push_back(v);
Instruction *call = CallInst::Create(newFloatFunc,
params.begin(), params.end(), "");
@@ -5605,7 +6171,6 @@
list.insert(list.begin(), assign);
list.insert(list.begin(), call);
- list.insert(list.begin(), load);
}
break;
@@ -6056,6 +6621,25 @@
return *cptr;
}
+extern "C"
+double
+rb_vm_float_value(VALUE obj)
+{
+ return RFLOAT_VALUE(obj);
+}
+
+/*
+ * Besides returning the actual immediate bits, if the object is a
+ * struct RFloat, we return FIXFLOAT_FLAG (even though it isn't fixed),
+ * so we know the object is a float value.
+ */
+extern "C"
+int
+rb_vm_effective_immediate_bits(VALUE obj)
+{
+ return rb_effective_immediate_bits(obj);
+}
+
static inline long
rebuild_new_struct_ary(const StructType *type, VALUE orig, VALUE new_ary)
{
@@ -6883,7 +7467,14 @@
#if ROXOR_COMPILER_DEBUG
printf("lvar %s\n", rb_id2name(id));
#endif
+#ifdef DEBUG_IR
+ std::string name("[lvar:");
+ name.append(rb_id2name(id));
+ name.push_back(']');
+ Value *store = new AllocaInst(RubyObjTy, name, bb);
+#else /* !DEBUG_IR */
Value *store = new AllocaInst(RubyObjTy, "", bb);
+#endif /* DEBUG_IR */
new StoreInst(nilVal, store, bb);
lvars[id] = store;
has_real_lvars = true;
Modified: MacRuby/branches/ticket159/compiler.h
===================================================================
--- MacRuby/branches/ticket159/compiler.h 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/compiler.h 2009-12-23 23:59:56 UTC (rev 3169)
@@ -100,6 +100,10 @@
std::map<std::string, GlobalVariable *> static_strings;
std::map<CFHashCode, GlobalVariable *> static_ustrings;
std::map<Function *, RoxorScope *> scopes;
+ std::map<GlobalVariable *, VALUE> global_values;
+#ifdef DEBUG_IR
+ std::map<std::string, GlobalVariable *> globals;
+#endif /* DEBUG_IR */
#if ROXOR_COMPILER_DEBUG
int level;
@@ -218,6 +222,10 @@
Function *setScopeFunc;
Function *setCurrentClassFunc;
Function *getCacheFunc;
+ Function *floatValueFunc;
+ Function *newFloatFunc;
+ Function *effectiveImmediateBitsFunc;
+ Function *zeroDivFunc;
Constant *zeroVal;
Constant *oneVal;
@@ -268,8 +276,13 @@
return compile_const_pointer(ptr, PtrPtrTy);
}
+#ifdef DEBUG_IR
Instruction *compile_protected_call(Value *imp,
+ std::vector<Value *> ¶ms, std::string *name=NULL);
+#else /* !DEBUG_IR */
+ Instruction *compile_protected_call(Value *imp,
std::vector<Value *> ¶ms);
+#endif /* DEBUG_IR */
void compile_dispatch_arguments(NODE *args,
std::vector<Value *> &arguments, int *pargc);
Function::ArgumentListType::iterator compile_optional_arguments(
@@ -319,9 +332,13 @@
virtual Value *compile_mcache(SEL sel, bool super);
Value *compile_get_mcache(Value *sel, bool super);
virtual Value *compile_ccache(ID id);
+#ifdef DEBUG_IR
+ virtual Value *compile_sel(SEL sel, bool add_to_bb=true);
+#else /* !DEBUG_IR */
virtual Value *compile_sel(SEL sel, bool add_to_bb=true) {
return compile_const_pointer(sel, PtrTy);
}
+#endif /* DEBUG_IR */
virtual Value *compile_id(ID id);
GlobalVariable *compile_const_global_string(const char *str,
const size_t str_len);
@@ -395,7 +412,7 @@
std::map<ID, GlobalVariable *> ids;
std::map<ID, GlobalVariable *> global_entries;
std::vector<GlobalVariable *> ivar_slots;
- std::map<VALUE, GlobalVariable *> literals;
+ std::map<std::string, std::pair<VALUE, GlobalVariable *> > literals;
GlobalVariable *cObject_gvar;
GlobalVariable *cStandardError_gvar;
Modified: MacRuby/branches/ticket159/include/ruby/intern.h
===================================================================
--- MacRuby/branches/ticket159/include/ruby/intern.h 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/include/ruby/intern.h 2009-12-23 23:59:56 UTC (rev 3169)
@@ -418,7 +418,6 @@
VALUE rb_objc_num_coerce_cmp(VALUE, VALUE, SEL sel);
VALUE rb_num_coerce_relop(VALUE, VALUE, SEL);
VALUE rb_float_new(double);
-VALUE rb_float_to_astr(VALUE);
VALUE rb_num2fix(VALUE);
VALUE rb_fix2str(VALUE, int);
VALUE rb_fix_minus(VALUE x, VALUE y);
@@ -457,6 +456,7 @@
VALUE rb_Array(VALUE);
double rb_cstr_to_dbl(const char*, int);
double rb_str_to_dbl(VALUE, int);
+bool rb_strict(void);
/* parse.y */
RUBY_EXTERN int ruby_sourceline;
RUBY_EXTERN char *ruby_sourcefile;
Modified: MacRuby/branches/ticket159/include/ruby/ruby.h
===================================================================
--- MacRuby/branches/ticket159/include/ruby/ruby.h 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/include/ruby/ruby.h 2009-12-23 23:59:56 UTC (rev 3169)
@@ -254,12 +254,14 @@
#else
// voodoo_float must be a function
// because the parameter must be converted to float
-static inline VALUE voodoo_float(float f)
+static inline VALUE
+voodoo_float(float f)
{
return *(VALUE *)(&f);
}
#define DBL2FIXFLOAT(d) (voodoo_float(d) | FIXFLOAT_FLAG)
#endif
+#define FLOAT_P(v) (rb_effective_immediate_bits((VALUE)(v)) == FIXFLOAT_FLAG)
#define FIXFLOAT_P(v) (((VALUE)v & IMMEDIATE_MASK) == FIXFLOAT_FLAG)
#define FIXFLOAT2DBL(v) coerce_ptr_to_double((VALUE)v)
@@ -291,7 +293,8 @@
// We can't directly cast a void* to a double, so we cast it to a union
// and then extract its double member. Hacky, but effective.
-static inline double coerce_ptr_to_double(VALUE v)
+static inline double
+coerce_ptr_to_double(VALUE v)
{
union {
VALUE val;
@@ -1410,6 +1413,23 @@
return BUILTIN_TYPE(obj);
}
+/*
+ * Besides returning the actual immediate bits, if the object is a
+ * struct RFloat, we return FIXFLOAT_FLAG (even though it isn't fixed),
+ * so we know the object is a float value. This is less work than calling
+ * TYPE() to see if it equals T_FLOAT. This is also used in the compiler;
+ * code is generated to call rb_effective_immediate_bits instead of simply
+ * ORing the last two bits.
+ */
+static inline int
+rb_effective_immediate_bits(VALUE obj)
+{
+ VALUE bits = (obj & IMMEDIATE_MASK);
+ if (bits || !RTEST(obj)) return bits;
+ if (*(VALUE *)obj == rb_cFloat) return FIXFLOAT_FLAG;
+ return 0;
+}
+
static inline void
__ignore_stupid_gcc_warnings(void)
{
Modified: MacRuby/branches/ticket159/io.c
===================================================================
--- MacRuby/branches/ticket159/io.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/io.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -3394,7 +3394,7 @@
}
tv->tv_sec = FIX2LONG(num);
}
- else if (TYPE(num) == T_FLOAT) {
+ else if (FLOAT_P(num)) {
double quantity = RFLOAT_VALUE(num);
if (quantity < 0.0) {
rb_raise(rb_eArgError, "select() does not accept negative timeouts.");
Modified: MacRuby/branches/ticket159/marshal.c
===================================================================
--- MacRuby/branches/ticket159/marshal.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/marshal.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -648,7 +648,7 @@
}
#endif
}
- else if (FIXFLOAT_P(obj)) {
+ else if (FLOAT_P(obj)) {
w_byte(TYPE_FLOAT, arg);
w_float(RFLOAT_VALUE(obj), arg);
}
@@ -759,11 +759,6 @@
}
break;
- case T_FLOAT:
- w_byte(TYPE_FLOAT, arg);
- w_float(RFLOAT_VALUE(obj), arg);
- break;
-
case T_STRING:
#if WITH_OBJC
w_uclass(obj, rb_objc_str_is_pure(obj), arg);
Modified: MacRuby/branches/ticket159/numeric.c
===================================================================
--- MacRuby/branches/ticket159/numeric.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/numeric.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -591,13 +591,17 @@
VALUE v;
double d;
} x = {.d = d};
- if (IMMEDIATE_P(x.v) == 0) return DBL2FIXFLOAT(d);
+ if (IMMEDIATE_P(x.v) == 0) return (x.v | FIXFLOAT_FLAG);
#endif
- NEWOBJ(flt, struct RFloat);
- OBJSETUP(flt, rb_cFloat, T_FLOAT);
+ return rb_box_fixfloat0(d);
+}
- flt->float_value = d;
- return (VALUE)flt;
+VALUE
+rb_float_new_retained(double d)
+{
+ VALUE val = rb_float_new(d);
+ GC_RETAIN(val);
+ return val;
}
/*
@@ -1213,7 +1217,7 @@
static VALUE
flo_eql(VALUE x, SEL sel, VALUE y)
{
- if (TYPE(y) == T_FLOAT) {
+ if (FLOAT_P(y)) {
double a = RFLOAT_VALUE(x);
double b = RFLOAT_VALUE(y);
@@ -1462,31 +1466,6 @@
return LONG2FIX(val);
}
-// used to serialize/deserialize literal floats
-
-VALUE
-rb_float_to_astr(VALUE num)
-{
- char buf[32]; // should be big enough for any %a string
- if (TYPE(num) != T_FLOAT) {
- rb_raise(rb_eArgError,
- "rb_float_to_astr called with argument that is not a float");
- }
- double d = RFLOAT_VALUE(num);
- snprintf(buf, sizeof(buf), "%a", d);
- return rb_str_new2(buf);
-}
-
-VALUE
-rb_float_from_astr_retained(const char *s)
-{
- double d = 0.0;
- sscanf(s, "%la", &d);
- VALUE v = DOUBLE2NUM(d);
- GC_RETAIN(v);
- return v;
-}
-
/*
* call-seq:
* num.floor => integer
@@ -1631,7 +1610,7 @@
}
}
}
- else if (TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) {
+ else if (FLOAT_P(from) || FLOAT_P(to) || FLOAT_P(step)) {
const double epsilon = DBL_EPSILON;
double beg = NUM2DBL(from);
double end = NUM2DBL(to);
@@ -2874,8 +2853,9 @@
static VALUE
bit_coerce(VALUE x)
{
- while (!FIXNUM_P(x) && TYPE(x) != T_BIGNUM) {
- if (TYPE(x) == T_FLOAT) {
+ int t;
+ while (!FIXNUM_P(x) && (t = TYPE(x)) != T_BIGNUM) {
+ if (t == T_FLOAT) {
rb_raise(rb_eTypeError, "can't convert Float into Integer");
}
x = rb_to_int(x);
Modified: MacRuby/branches/ticket159/object.c
===================================================================
--- MacRuby/branches/ticket159/object.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/object.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -19,6 +19,8 @@
#include <ctype.h>
#include <math.h>
#include <float.h>
+#include "onig/onigposix.h" // oniguruma version of regcomp/regexec
+#include <libkern/OSAtomic.h>
#include "objc.h"
#include "vm.h"
@@ -2571,6 +2573,37 @@
if (!p) return 0.0;
q = p;
while (ISSPACE(*p)) p++;
+ if (rb_strict()) {
+ /*
+ * In strict mode, before we call strtod, we need to check if the
+ * string begins with "0x" (a possible floating hex string) or
+ * "inf[inity]" or "nan" (ignoring case, and with optional preceding
+ * sign), and return an appropriate zero or error.
+ */
+ static regex_t re_hex;
+ static regex_t re_str;
+ static bool inited = false;
+ static OSSpinLock lock = OS_SPINLOCK_INIT;
+
+ if (!inited) {
+ OSSpinLockLock(&lock);
+ if (!inited) {
+ assert(regcomp(&re_hex, "^[-+]?0x",
+ REG_EXTENDED | REG_ICASE) == 0);
+ assert(regcomp(&re_str, "^[-+]?(inf|nan)",
+ REG_EXTENDED | REG_ICASE) == 0);
+ inited = true;
+ }
+ OSSpinLockUnlock(&lock);
+ }
+ if (regexec(&re_hex, p, 0, NULL, 0) == 0) {
+ return *p == '-' ? -0.0 : 0.0;
+ }
+ if (regexec(&re_str, p, 0, NULL, 0) == 0) {
+ if (badcheck) goto bad;
+ return 0.0;
+ }
+ }
d = strtod(p, &end);
if (errno == ERANGE) {
OutOfRange();
Modified: MacRuby/branches/ticket159/ruby.c
===================================================================
--- MacRuby/branches/ticket159/ruby.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/ruby.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -456,6 +456,36 @@
rb_warn("don't know how to dump `%.*s', (insns)", len, str);
}
+/*
+ * MacRuby strict mode. This is to disable macruby extensions, such as
+ * %a in sprintf or interpretation of floating point hex, "inf[inity]" and
+ * "nan" by to_f.
+ */
+static bool macruby_strict = false;
+static bool macruby_strict_inited = false;
+
+static inline void
+rb_set_strict(void)
+{
+ macruby_strict = true;
+ macruby_strict_inited = true;
+}
+
+bool
+rb_strict(void)
+{
+ if (!macruby_strict_inited) {
+ char *val = getenv("MACRUBY_STRICT");
+ if (val && strcasecmp(val, "no") != 0
+ && strcasecmp(val, "false") != 0
+ && strcmp(val, "0") != 0) {
+ macruby_strict = true;
+ }
+ macruby_strict_inited = true;
+ }
+ return macruby_strict;
+}
+
static int
proc_options(int argc, char **argv, struct cmdline_options *opt)
{
@@ -736,6 +766,9 @@
encoding:
opt->ext.enc.name = rb_str_new2(s);
}
+ else if (strcmp("strict", s) == 0) {
+ rb_set_strict();
+ }
else if (strcmp("version", s) == 0) {
opt->version = 1;
}
Modified: MacRuby/branches/ticket159/sprintf.c
===================================================================
--- MacRuby/branches/ticket159/sprintf.c 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/sprintf.c 2009-12-23 23:59:56 UTC (rev 3169)
@@ -950,6 +950,10 @@
case 'a':
case 'A':
+ if (rb_strict()) {
+ rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
+ }
+ /* drop through */
case 'f':
case 'g':
case 'G':
Modified: MacRuby/branches/ticket159/vm.cpp
===================================================================
--- MacRuby/branches/ticket159/vm.cpp 2009-12-23 22:08:20 UTC (rev 3168)
+++ MacRuby/branches/ticket159/vm.cpp 2009-12-23 23:59:56 UTC (rev 3169)
@@ -149,6 +149,7 @@
return mm->getGOTBase();
}
+#if !LLVM_TOT
void SetDlsymTable(void *ptr) {
mm->SetDlsymTable(ptr);
}
@@ -156,6 +157,7 @@
void *getDlsymTable() const {
return mm->getDlsymTable();
}
+#endif
uint8_t *startFunctionBody(const Function *F,
uintptr_t &ActualSize) {
@@ -242,7 +244,12 @@
InitializeNativeTarget();
std::string err;
+#if LLVM_TOT
+ ee = ExecutionEngine::createJIT(emp, &err, jmm, CodeGenOpt::None, false,
+ CodeModel::Default);
+#else
ee = ExecutionEngine::createJIT(emp, &err, jmm, CodeGenOpt::None, false);
+#endif
if (ee == NULL) {
fprintf(stderr, "error while creating JIT: %s\n", err.c_str());
abort();
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20091223/68f677f3/attachment-0001.html>
More information about the macruby-changes
mailing list