Skip to content

Give a cppia member field declared Bool its boolean storage - #1367

Open
MeguminBOT wants to merge 1 commit into
HaxeFoundation:masterfrom
MeguminBOT:fix-cppia-bool-member-storage
Open

Give a cppia member field declared Bool its boolean storage#1367
MeguminBOT wants to merge 1 commit into
HaxeFoundation:masterfrom
MeguminBOT:fix-cppia-bool-member-storage

Conversation

@MeguminBOT

Copy link
Copy Markdown

The problem

A class member declared Bool in a cppia module gets an integer slot, so reading it back through
reflection gives you 1 instead of true. A static field of the same declared type, in the same
module, gives you true:

member 1, static true

Conditions and comparisons still work, since they are happy with the integer. Anything that looks at
the value itself does not.

Why

CppiaVar::linkVarTypes has two forms:

  • The static form calls fieldStorageFromType, which has a case for Bool and returns fsBool.
  • The member form switches on exprType instead. By the time it runs, TypeData::link has
    already mapped the Bool type name to etInt, so the field ends up as fsInt.

That is why the two fields above disagree.

The fix

In src/hx/cppia/CppiaVars.cpp, the member form now calls fieldStorageFromType too:

storeType = typeId==0 ? fsObject : fieldStorageFromType(type);

switch(storeType)
{
   case fsBool: ioOffset += sizeof(int); break;
   case fsByte: ioOffset += sizeof(int); break;
   case fsInt: ioOffset += sizeof(int); break;
   case fsFloat: ioOffset += sizeof(Float); break;
   case fsString: ioOffset += sizeof(String); break;
   case fsObject: ioOffset += sizeof(hx::Object *); break;
   case fsUnknown:
      break;
}

The slot is still int sized, so the layout and the AlignOffset call above it do not change.

Test

test/cppia covers it. ClientBoolField in Client.hx holds a Bool member and a Bool static,
and testBoolMemberStorage in cases/TestCommon.hx reads both back through Reflect.field.

cd test/cppia
haxe compile-host.hxml
haxe compile-client.hxml
cd bin && ./CppiaHost.exe client.cppia

Without the fix that test fails with Member Bool did not read back as a boolean, and the static
assertion beside it still passes, which is the pair that shows the two forms disagreeing. Same result
with or without -jit.

Reproducing by hand

Script.hx, built with haxe -m Script --cppia script.cppia:

class Holder {
   public var flag:Bool = true;
   public static var staticFlag:Bool = true;
   public function new() {}
}

class Script {
   public static function run():String {
      return 'member ' + Std.string(Reflect.field(new Holder(), 'flag'))
         + ', static ' + Std.string(Reflect.field(Holder, 'staticFlag'));
   }

   public static function main():Void {}
}

Load it from a host built with -D scriptable, using
cpp.cppia.Module.fromData(bytes).boot(), and call Script.run through reflection.

result
before member 1, static true
after member true, static true

Same result with the JIT on or off, since the storage is decided at link time.

Let me know if I got anything wrong!

CppiaVar::linkVarTypes has two forms. The static form asks fieldStorageFromType, which
answers fsBool for Bool. The member form switches on exprType instead, and TypeData::link
has already mapped Bool onto etInt by the time it runs, so the field is laid out as fsInt
and reads back through reflection as 1 rather than true.

The member form now asks fieldStorageFromType as well. The slot stays the size of an int,
leaving the layout and the AlignOffset call above it unchanged.

The cppia test suite covers it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant