Note that this does NOT completely test the full range of if instructions for abstract relational comparison. Notably, the Adobe Animate CC compiler compiles each operator into it's negated equivalent, e.g. `<` becomes `ifnlt`.
I do not know how to get it to emit `ifge` or the like, which differ only by how they handle `NaN`s.
The test is also far more in-depth than the `if_eq`/`if_ne` tests, which use the same set of vectors as the strict-equality tests from a while ago. Interestingly, this test passed on first run
Implementation is limited to generating exceptions on `null` or `undefined`. I'm not sure if primitive values don't exist in AVM2 or if this is supposed to box them like ES3, so I have decided to handle neither at this time.
This code is slightly over/under-precise compared to AVM2. This is because we handle precision limiting in binary floats rather than as part of the float printing process. Flash Player may also be rounding differently than us. However, I'm pretty sure ECMA-262 allows us to slightly differ here.
The ECMA-262 documentation is awfully overwrought for something that boils down to "chop off the non-whole part, wrap to 32 bits, then reinterpret as signed". Bitwise operations are *hell* to describe mathematically, and such descriptions are even harder to understand.
The underlying problem is actually shift overflow - on the fifth byte in the sequence, it attempts to mask bits by shifting them off the left of the value, which doesn't work here, as we'll be shifting by -3. For those unaware, shifting by a negative does NOT shift in the opposite direction, it instead gives your C compiler permission to stuff demons up your nose.
I wouldn't be surprised if this is just outright UB in Flash Player.
For whatever reason, `pushbyte` appears to be processed as a *signed* byte, despite the clear wording of "*byte_value* is an unsigned byte" in avm2overview.pdf. I guess it's supposed to be manually converted and promoted in this manner.
As compiled by Adobe Animate CC 2020, this test appears to only use `iffalse`. However, both `op_is_false` and `op_is_true` coerce in the same manner, so I'm not entirely sure this is a problem for now.
Functions that need to assert Boolness without coercion should either:
1. Ensure their function declaration requires a Boolean. (We don't enforce type errors on ES4 typehints yet, but we should.)
2. Check the value type themselves and raise their own errors if necessary.
As it stands the only users of `as_bool` either needed to check the type themselves or use `coerce_to_bool`. Notably, `setPropertyIsEnumerable` doesn't appear to coerce *or* throw an error: it instead fails silently if you hand it a non-`Boolean` value.
Notably, all of the `Avm1` "run stack frame" functions can no longer take a self parameter as the update context they will be getting also has that same parameter. Ergo, they're associated functions that get the moral equivalent of self from the update context.
This also introduces a new `Activation::from_stub` which creates a stub frame that runs everything on the main movie in layer 0. This significantly reduces boilerplate code elsewhere in the project.
This also removes the function parameter on `sort_compare_numeric`. As it was only being used for string comparisons, and it was causing unfixable lifetime issues, I have instead had it take the case-sensitivity flag and call the two functions it would have been passed anyway. This fixes the lifetime issue.