Remove back pointer from Real to VALUE#344
Conversation
d30582e to
ecac757
Compare
ecac757 to
86a84a6
Compare
86a84a6 to
e75cb08
Compare
tompng
left a comment
There was a problem hiding this comment.
Most diffs are just a line-by-line conversion.
I commented where it is not a line-to-line conversion.
| { | ||
| ENTER(1); | ||
| Real *p; | ||
| BDVALUE v; |
There was a problem hiding this comment.
Real *p Real *pv Real *vp is renamed to v in this pull request.
I think p represents that it's a pointer.
| bdvalue_nullable(BDVALUE v) | ||
| { | ||
| return (NULLABLE_BDVALUE) { v.bigdecimal, v.real }; | ||
| } |
There was a problem hiding this comment.
BDVALUE NULLABLE_BDVALUE bdvalue_nonnullable bdvalue_nullable are introduced to reduce the possibility of bugs like this:
- Real *a = GetVpFooBarOrNull(x);
- if (a != NULL) return Baz(a);
+ BDVALUE a = GetFooBarOrNull(x);
+ if (a != NULL) return Baz(a.real); // Should be `if (a.real != NULL)`, but hard to detectUsing NULLABLE_BDVALUE:
BDVALUE a = GetFooBarOrNull(x); // Bug. Compile error
NULLABLE_BDVALUE a = GetFooBarOrNull(x); // OK
if (a != NULL) return Baz(a); // Bug. Compile error
if (a != NULL) return Baz(a.real); // Bug. Compile error
if (a != NULL) return Baz(a.real_or_null); // Bug. We can find this bug by grep
if (a.real_or_null != NULL) return Baz(a.real_or_null); // OKThe only dangerous parts are:
- Where accessing unassigned
BDVALUE - Where using
v.real_or_nullv.bigdecimal_or_nil - Where using
bdvalue_nonnullable(x)
| GetBDValueWithPrecMust(VALUE v, long prec) | ||
| { | ||
| return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1)); | ||
| } |
There was a problem hiding this comment.
Real *real = GetVpValueWithPrec(v, prec, must=1);
Real *real_or_null = GetVpValueWithPrec(v, prec, must=0);
Real *real = GetVpValue(v, must=1)
Real *real_or_null = GetVpValue(v, must=0)
// ↓
BDVALUE x = GetVpValueWithPrecMust(v, prec);
NULLABLE_BDVALUE y = GetVpValueWithPrec(v, prec);
BDVALUE x = GetVpValueMust(v);
NULLABLE_BDVALUE y = GetVpValue(v);
// x.real, x.bigdecimal: always non-null/non-nil (except unassigned case)
// y.real_or_null, y.bigdecimal_or_nil| VP_EXPORT Real * | ||
| VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception) | ||
| static NULLABLE_BDVALUE | ||
| CreateFromString(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception) |
There was a problem hiding this comment.
VpNewRbClass, VpCreateRbObject → CreateFromString
The important part of this function is that it creates from string. The original function name doesn't represent it.
Merged these two functions into one because I couldn't think of a good name.
| b = bdvalue_nonnullable(b2); | ||
| } | ||
|
|
||
| if (!b) return DoSomeOne(self,r,'+'); |
There was a problem hiding this comment.
moved to else clause above
| static Real * | ||
| rbd_reallocate_struct(Real *real, size_t const internal_digits) | ||
| static BDVALUE | ||
| rbd_reallocate_struct(BDVALUE value, size_t const internal_digits) |
There was a problem hiding this comment.
Take a pair of BigDecimal object and Real*, returns a pair of BigDecimal object and reallocated Real*
| rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits) | ||
| { | ||
| return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true); | ||
| return bdvalue_nonnullable(rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true)); |
There was a problem hiding this comment.
rbd_allocate_struct_zero_wrap_klass can return null, but bigdecimal.c is/was assuming that the value is non-nullable.
This change just makes the fact clear.
| typedef struct { | ||
| VALUE bigdecimal; | ||
| Real *real; | ||
| } BDVALUE; |
There was a problem hiding this comment.
BDVALUE: BigDecimal VALUE (+ Real*)
A pair of VALUE(instance of BigDecimal) and Real*.
|
|
||
| static VALUE | ||
| VpCheckGetValue(Real *p) | ||
| CheckGetValue(BDVALUE v) |
There was a problem hiding this comment.
Takes BDVALUE, checks exception and returns bigdecimal.
| Real *new_real = (Real *)ruby_xrealloc(value.real, size); | ||
| new_real->MaxPrec = internal_digits; | ||
| if (obj) { | ||
| new_real->obj = 0; |
There was a problem hiding this comment.
Real does not have obj field anymore. Set/Reset/Validate real->obj is removed.
((Real*)x)->obj, a reference from DATA to VALUE, will be garbled after gc compaction. Real should not hold a reference to VALUE.
e75cb08 to
489cd85
Compare
Fixes #340
((Real*)x)->obj, a reference from DATA to VALUE, will be garbled after gc compaction. Real should not hold a reference to VALUE.Most diffs are just a line-by-line conversion.
Introduce
BDVALUE, a pair of BigDecimal VALUE and struct Real, instead of relying on VALUE reference from struct Real.BDVALUE_OR_NILis an nullable version ofBDVALUE.This is to reduce the possibility of embedding new bugs in this pull request.
GUARD_OBJis not so important after this change. We can remove most of them and replace it to fewRB_GC_GUARD.But in this pull request, these are left as is, to make review easier.