Open ghost opened 2 years ago
This also affects all users of EnterStubFrame
:
https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/assembler/assembler_ia32.cc#L2732-L2734
Such as: https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/stub_code_compiler_ia32.cc#L70-L72 Which clearly doesn't do the same as it does in the other architectures.
... we incorrectly set the Code object in Dart frames to the current Code ...
There may be a misunderstanding here. The code object in a frame is representing the code object of that frame's function (not the caller's code object).
On most of our architectures (x64, arm, arm64) the caller is populating this code object as part of the call sequence: In order to call a function, the caller has to load the Function
s Code
and from there the Code
s entrypoint
address. The caller therefore has to load the code object anyway, so it loads it into the specified CODE_REG
register - which makes it available to the callee (i.e. the callee can simply push CODE_REG
- which is its own code object).
Now on ia32 we do not use code objects as such. Callers (e.g. a static call) will invoke its target directly - no need to get the entrypoint from a code object. The callee therefore has to get it's own code object in a different way, namely in the way you described above.
This is by-design.
assembler_ia32.h
has a field,code_
, which is not present in any of the other assemblers:https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/assembler/assembler_ia32.h#L1093
It is only read in one place: https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/assembler/assembler_ia32.cc#L2699-L2704
And set in one place: https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/object.cc#L17254-L17256
Note how we're setting the field through a getter: https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/assembler/assembler_ia32.h#L1046
This is already fishy, but this quirk is also causing a different bug, whereby we incorrectly set the Code object in Dart frames to the current Code, instead of the Code being called.
For example, in
FfiCallInstr
we commonly do the following across all architectures: https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/backend/il_ia32.cc#L1039-L1041Except, on IA32
EnterDartFrame
calls the abovePushCodeObject
which we saw always pushes whatever is incode_
, and not what is inCODE_REG
, as the comment otherwise claims (which is correct on other archs.): https://github.com/dart-lang/sdk/blob/618db8a41d68fd37ff5bb228c69486721be3a636/runtime/vm/compiler/assembler/assembler_ia32.cc#L2706-L2709This ultimately has the effect that FFI ExitFrames have a duplicate FfiTrampoline Code object in them where they should have Null, which in turn affects stack traces, etc.
Aside: This might also affect other users of
EnterDartFrame
, but I haven't checked.