[love.js development] Cannot push love object to Lua error

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Davidobot
Party member
Posts: 1226
Joined: Sat Mar 31, 2012 5:18 am
Location: Oxford, UK
Contact:

[love.js development] Cannot push love object to Lua error

Post by Davidobot »

Hi, long time no see.

I've recently been trying to get the wonderful love.js running with the latest versions of both LÖVE and Emscripten. I've nearly cracked the puzzle (repo here) but I'm getting a very similar error to this recent post, i.e.

Code: Select all

Error: main.lua:31: Cannot push love object to Lua: unexpected alignment (pointer is 0xd9a258 but alignment should be 16)
love.js:9 stack traceback:
love.js:9 	[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
love.js:9 	[C]: in function 'newImage'
love.js:9 	main.lua:31: in main chunk
love.js:9 	[C]: in function 'require'
love.js:9 	[string "boot.lua"]:570: in function <[string "boot.lua"]:380>
love.js:9 	[C]: in function 'xpcall'
love.js:9 	[string "boot.lua"]:787: in function <[string "boot.lua"]:780>
love.js:9 	[C]: in function 'xpcall'
and

Code: Select all

Error: Cannot push love object to Lua: unexpected alignment (pointer is 0xa72a88 but alignment should be 16)
love.js:9 stack traceback:
love.js:9 	[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
love.js:9 	[C]: ?
love.js:9 	[C]: in function 'setNewFont'
love.js:9 	[string "boot.lua"]:674: in function 'handler'
love.js:9 	[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
love.js:9 	[C]: in function 'newImage'
love.js:9 	main.lua:31: in main chunk
love.js:9 	[C]: in function 'require'
love.js:9 	[string "boot.lua"]:570: in function <[string "boot.lua"]:380>
love.js:9 	[C]: in function 'xpcall'
love.js:9 	[string "boot.lua"]:787: in function <[string "boot.lua"]:780>
love.js:9 	[C]: in function 'xpcall'
Something similar also happened with wrap_Maths, but I "solved" it by forcing 64-bit on compilation of love and all of the dependencies (which is not the way to go).

I was wondering if there is any insight into why this is happening and perhaps a solution anyone has encountered?
PM me on here or elsewhere if you'd like to discuss porting your game to Nintendo Switch via mazette!
personal page and a raycaster
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: [love.js development] Cannot push love object to Lua error

Post by pgimeno »

I've made a patch for Löve to make it work as long as pointer alignment is 2 or more, I'm not sure how much interest there is in it though. I already offered a similar one and there was no interest in it.

Code: Select all

diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp
index 36f1ddce..8f1ffd4d 100644
--- a/src/common/runtime.cpp
+++ b/src/common/runtime.cpp
@@ -101,28 +101,41 @@ static lua_Number luax_computeloveobjectkey(lua_State *L, love::Object *object)
 {
 	// love objects should be allocated on the heap, and thus are subject
 	// to the alignment rules of operator new / malloc. Lua numbers (doubles)
-	// can store all possible integers up to 2^53. We can store pointers that
-	// use more than 53 bits if their alignment is guaranteed to be more than 1.
-	// For example an alignment requirement of 8 means we can shift the
-	// pointer's bits by 3.
-	const size_t minalign = LOVE_ALIGNOF(std::max_align_t);
-	uintptr_t key = (uintptr_t) object;
-
+	// can store up to 63 bits of information as long as the exponent is
+	// guaranteed to not be all 0's (denormal) nor all 1's (infinity, NaN).
+	// We need all these conditions for using doubles to store pointers:
+	//  - Min pointer alignment is 2.
+	//  - lua_Number is an IEC-559 double
+	//  - Doubles and 64-bit integers are the same size and endianess
+	//  - Pointers fit in 64 bits
+	// We map key bits from input pointer as follows:
+	//   63 <- 63 (sign)
+	//   62 <- !62 (exponent highest bit)
+	//   61 <- 62 (exponent second highest bit)
+	//   60 <- 61
+	//   etc.
+	//   0 <- 1
+	// Since bits 61 and 62 are always opposite, the exponent can't be all 1's
+	// or all 0's, thus avoiding special numbers like denormals and NaNs and
+	// making the floats safe.
+	const size_t minalign = 2;
+	static_assert(LOVE_ALIGNOF(std::max_align_t) >= minalign);
+	static_assert(std::numeric_limits<lua_Number>::is_iec559);
+	static_assert(sizeof(lua_Number) == sizeof(uint64_t));
+	static_assert(sizeof(uint64_t) >= sizeof(uintptr_t));
+
+	uint64_t key = (uint64_t)object;
 	if ((key & (minalign - 1)) != 0)
 	{
 		luaL_error(L, "Cannot push love object to Lua: unexpected alignment "
 				   "(pointer is %p but alignment should be %d)", object, minalign);
 	}
 
-	static const size_t shift = (size_t) log2(LOVE_ALIGNOF(std::max_align_t));
-
-	key >>= shift;
-
-	// Make sure our key isn't larger than 2^53.
-	if (key > 0x20000000000000ULL)
-		luaL_error(L, "Cannot push love object to Lua: pointer value %p is too large", object);
-
-	return (lua_Number) key;
+	key = (key & 0xC000000000000000ULL) ^ 0x4000000000000000ULL;
+	key |= ((uint64_t)object >> 1) & 0x3FFFFFFFFFFFFFFFULL;
+	lua_Number fkey;
+	memcpy(&fkey, &key, sizeof(fkey));
+	return fkey;
 }
 
 static int w__release(lua_State *L)
User avatar
slime
Solid Snayke
Posts: 3132
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: [love.js development] Cannot push love object to Lua error

Post by slime »

It sounds like emscripten's std::max_align_t on 32 bit might not have the correct value (or the documentation for it was misleading enough that love's code is using it incorrectly). You could try replacing the LOVE_ALIGNOF(std::max_align_t) lines with LOVE_ALIGNOF(8) (on 32 bit systems), although I'm not sure if that will work on all 32 bit platforms.
User avatar
Davidobot
Party member
Posts: 1226
Joined: Sat Mar 31, 2012 5:18 am
Location: Oxford, UK
Contact:

Re: [love.js development] Cannot push love object to Lua error

Post by Davidobot »

pgimeno wrote: Fri Jul 03, 2020 11:35 pm I've made a patch for Löve to make it work as long as pointer alignment is 2 or more, I'm not sure how much interest there is in it though. I already offered a similar one and there was no interest in it.

Code: Select all

...
Thanks pgimeno! This worked for me. The port is actually nearly complete, with the exception of audio!
slime wrote: Sat Jul 04, 2020 12:56 am It sounds like emscripten's std::max_align_t on 32 bit might not have the correct value (or the documentation for it was misleading enough that love's code is using it incorrectly). You could try replacing the LOVE_ALIGNOF(std::max_align_t) lines with LOVE_ALIGNOF(8) (on 32 bit systems), although I'm not sure if that will work on all 32 bit platforms.
I'll look into this too, probably will bring it up as an issue there. Thank you!
PM me on here or elsewhere if you'd like to discuss porting your game to Nintendo Switch via mazette!
personal page and a raycaster
Post Reply

Who is online

Users browsing this forum: No registered users and 194 guests