I’m working on implementing a 64bit integer class for our devices and I keep getting the following error whenever I call the multiplication metamethod:
“ERROR: halting stuck metamethod”
Does anybody know what this error means or better yet what could be causing it? I cannot seem to find any documentation for it nor do I have any idea what could be causing it. If I run the same code as a separate function rather than a metamethod it works just fine.
Any help would be much appreciated.
The relevant code is:
`
class int64{
_v = blob(8);
constructor(v){
_v = blob(8);
if(typeof(v)=="blob" || typeof(v)=="string")
for(local i = 0; i<8 && i<v.len(); i++)
if(typeof(v)=="string")
_v[v.len()-1-i] = v[i];
else
_v[i] = v[i];
else if(typeof(v)=="integer"){
_v.writen(v,'i');
if(v<0)
_v.writen(0xffffffff,'i');
}
}
// Multiplication Metamethod
function _mul(y){
local b = blob(8);
for(local i = 0; i<8; i++){
local n=0;
for(local j = 0; (i+j)<8; j++)
b[i+j] = n = b[i+j] + (_v[i])*(y._v[j]) + (n>>8); // NB: carry = n>>8
}
return int64(b);
}
// To String Metamethod
function _tostring(){
_v.seek(0);
local vl = _v.readn('i');
local vh = _v.readn('i');
return (vh==0)?format("0x%02x",vl):format("0x%x%08x",vh,vl);
}
// Other functions...
What’s happening here is that your Squirrel agent code gets run in a time-slicing system with everybody else’s Squirrel agent code. And, for technical reasons, Squirrel can’t be time-sliced while executing a metamethod. So each metamethod call is itself limited to one time-slice (1,000 Squirrel bytecode instructions) before it gets aborted as a potential CPU hog, i.e. as potentially unfair to other agents running on the same system. There’s no way around this other than to make the metamethod use fewer instructions; in the specific case of int64 multiply, you could try doing the calculation 16 bits at a time instead of 8. Or just do the calculation in a non-metamethod function.
Device-side Squirrel code, which can’t be “unfair” to anyone except itself and so is not time-sliced, does not have this restriction.
I think smittytone’s meaning is that you can get yourself in trouble using the built in operands. For example: x1 <- 1234; x2 <- int64(5678); x3 <- x1*x2; //Fails because integer type doesn't know how to handle int64s x4 <- x2*x1; //Succeeds x5 <- x2*1 //Fails because _mul assumes op
As longs as you don’t ever mix data types you should be ok for short operations as Peter points out.
I’ve actually been working on an arbitrary precision signed integer class which could be used for 64-bit variables but it only supports addition and subtraction, but you can find the code here if it’s helpful:
@brandon Right I get you. Good point I will take note to remember that.
And neat. Nice to see somebody else working on a similar problem. Out of curiosity did you avoid adding multiplication for similiar reasons? Shrinking the multiplication function down to less operations is proving harder than I thought, even switching the arithmetic to 16 bits rather than 8.
I did wonder at one point about providing bignum support in Squirrel. Normally I’m dead against such things, at least in device Squirrel, because it uses up precious improm space (costing everyone) for something that could in theory be implemented as a Squirrel library on top (costing only those people who use it). But in this case the improm already contains a four-function bignum library, because the RSA cryptography used by its TLS connection demands one.
Ok thanks for the help. I’ve reworked the class and got the multiplication function working now. Thanks for the help.
I do have one further question about executing metamethods on the agents.
If I run the sequence of test code on my int64 class below it runs just fine but if I add one of the commented out ‘server.log(-n3);’ lines I get the “ERROR: halting stuck metamethod” again which seems unexpected. There is nothing wrong with the line itself: its already in the sequence 4 times, but that particular positioning of it causes it to fail. What could be happening here?
My thought was that the _tostring() metamethod was being called towards the end of a time slice and thus being cut off partway through, in spite of easily fitting within a time slice. If so does this mean that any metamethod can randomly (or at least unexpectedly) fail and cause this error?
n1 <- int64(78274); server.log(n1); n2 <- int64(0x7f012); server.log(n2); n3 <- n1*n2; server.log(-n3); // Call this line once it works fine. Call it again and it fails // server.log(-n3); // Uncomment this and I get "ERROR: halting stuck metamethod" here server.log(n3); server.log(-n3); server.log(-n3); server.log(-n3); // Seems I can call the line 3 times before failing here... // server.log(-n3); // Uncomment this and I get "ERROR: halting stuck metamethod" here