Android and Select

Monkey Forums/Monkey Bug Reports/Android and Select

eme64(Posted 2013) [#1]
Hi everyone

I have now tryed debugging my long code for over 3 hours and don't quite understand what the problem is. I however suspect it must have to do with some sort of limit on the Android platform as to how many select-commands (or case) I used.

My App crashes only on Android (and not on HTML5), before any code of mine is even executed. I have been commenting out some big blocks of code and if they are big enaugh, the problem does not occour.

The Debug Log sais this:
java.lang.VerifyError: com/eme64/dingko001/c_TCode_String_Function
at com.eme64.dingko001.bb_.bbInit(MonkeyGame.java:16403)
at com.eme64.dingko001.MonkeyGame.onCreate(MonkeyGame.java:1499)

I am working with Version 74a, will soon try it with 75d.

Thanks in advance
eme64


Something else that worries me:
[javac] Note: C:\Users\Emanuel\Dropbox\Game Project\Monkey Dingko New\game.build\android\src\com\eme64\dingko001\MonkeyGame.java uses unchecked or unsafe operations


eme64(Posted 2013) [#2]
No difference with 75d unfortunately.

I would like to give you code, but I cannot give you 6648 Lines of code.


slenkar(Posted 2013) [#3]
Can you try to comment more lines to narrow down the problem?


Goodlookinguy(Posted 2013) [#4]
Select-Case statements are converted to if-else blocks by Monkey. So a select-case limit on Android is not your problem.


eme64(Posted 2013) [#5]
Well I would like to narrow it down, but unfortunately I was not able to do so. As I said, not one line of my code is being run (tested it with print). If I run it with HTML5 it works just fine.
Now, I have tryed to comment some "case"s out, and have done it multiple times at multiple locations, that do not have much to do with each other. When I remove enaugh Code, it works, but it seems not to depend on which code in particular I remove and that is the problem. So I concluded since it is not because the code does somthing wrong it must be somehow too much, and if some code is cut out, it is no longer too much. But of course it could still be, that there is a connection between these locations, that I missed.
Maybe someone can tell me what this meens:
java.lang.VerifyError: com/eme64/dingko001/c_TCode_String_Function

That could narrow down the possible locations that could cause the problem.

Many thanks
eme64


SLotman(Posted 2013) [#6]
Are you trying to load or even draw stuff on OnCreate?

You shouldn't - and your program is crashing exactly on OnCreate... what exactly are you doing on OnCreate?
(Note that some targets are more forgiving than others, so if something works on HTML5 or even on GLFW, doesn't mean it will work on iOS or Android, where memory and speed resources are much lower)


eme64(Posted 2013) [#7]
This is my main():
Function Main:Int()
	#If EME_DEBUG = "true" then
	Print "#############"
	Print ""
	Print "Debug Mode On"
	Print ""
	Print "#############"
	#endif
	
	Print "WASD - F1 for Debug-View"
	
	New Game()
	
	Return true
End Function


This my onCreate:
 Method OnCreate:Int()
    	
    	'Debug Log
		Game.debug_log_list = New String[Game.debug_log_max]
		
    	For Local i:Int = 0 To Game.debug_log_max-1
    		Game.debug_log_list[i] = String.FromChar(0)
    	Next
    	
    	'Mouse
    	MOUSE.init()
    	
    	
    	#If TARGET="android" Or TARGET="ios" 'admob !
    	Self.admob=Admob.GetAdmob()
        Self.admob.ShowAdView 1,Self.ad_layout
        #Endif
        
        
    	SetVirtualDisplay Game.res_x, Game.res_y
    	
		SetUpdateRate 30
		
		Self.last_minute = Millisecs()
		
		Return true
    End Method


This the MOUSE.init()
Function init:Int()
		MOUSE.x = New Float[3]
		MOUSE.y = New Float[3]
		MOUSE.typ = New Int[3]
		Return true
	End function


I do not see the app crash in any of that, at least I should get the
Print "WASD - F1 for Debug-View"


The app crashes because of code in the OnUpdate(), or at least if I remove parts of it it does noch crash any more. In all the Bugs that I created myself the app at least started to run and I could find out where with stragegically placed "print"s.

Could anyone please tell me what this means?
java.lang.VerifyError: com/eme64/dingko001/c_TCode_String_Function



eme64(Posted 2013) [#8]
ah, I now see what it meens:
TCode_String_Function
it is a Class in my code.

How I "fixed" the problem now. Pseudocode:
Method get:string(someinput)
	select txt
		case "a"
		case "b"
		...
		case "n"
		'crashed with case "n+1"
		default
			self.get2(someinput)
	endselect
end Method

Method get2:string(someinput)
	select txt
		case "n+1"
		
	endselect
end Method


The "solution" was simply to move the code that seems to create the problem. But remember, this code is not even run once, and it is even in the OnUpdate(). What could cause this?

One thing I could think of:
I reuse variablenames and redefine them for different Classes within one Select-Block
Example:
Select True
	Case TSkin_Collision_Rect(TSkin.skins[skin].collision) <> null
		Local p:TSkin_Collision_Rect = TSkin_Collision_Rect(TSkin.skins[skin].collision)
		Return String(y + scale_y*(p.y1 + p.y2)/2.0)
	Case TSkin_Collision_Circle(TSkin.skins[skin].collision) <> null
		Local p:TSkin_Collision_Circle = TSkin_Collision_Circle(TSkin.skins[skin].collision)
		Return String(y + scale_y*p.y)
	Case TSkin_Collision_Points(TSkin.skins[skin].collision) <> null
		Local p:TSkin_Collision_Points = TSkin_Collision_Points(TSkin.skins[skin].collision)
		Local y1:Float = p.yl[0]
		Local y2:Float = p.yl[p.yl.Length()/2]
	Return String(y + scale_y*(y1 + y2)/2.0)
End Select


So "p" is reused for different Classes. And I do this a lot. How is this translated? Could this possibly be the problem?


Goodlookinguy(Posted 2013) [#9]
Here's something interesting: http://stackoverflow.com/questions/100107/reasons-of-getting-a-java-lang-verifyerror

You would get this error if the bytecode size of your method exceeds the 64kb limit; but you would probably have noticed that.
This might be your problem. Refactor your code into more reusable chunks.


SLotman(Posted 2013) [#10]
Why you're doing this:

	Game.debug_log_list = New String[Game.debug_log_max]
		
    	For Local i:Int = 0 To Game.debug_log_max-1
    		Game.debug_log_list[i] = String.FromChar(0)
    	Next


Strings as far as I know are initialized with zero length, so you don't need to do a Game.debug_log_list[i] = anything. I would at least comment out everything with this debug_log_list first and foremost, since this is a string, and your error shows a problem with strings on OnCreate.

Secondly... I really think this should be on OnUpdate. You can't guarantee admob will be initialized when your program is being created. Comment it out to see if your program runs.

	#If TARGET="android" Or TARGET="ios" 'admob !
    	Self.admob=Admob.GetAdmob()
        Self.admob.ShowAdView 1,Self.ad_layout
        #Endif


Third...

This one, for sure must be on OnRender, and should be always called on every render frame.
    	SetVirtualDisplay Game.res_x, Game.res_y



eme64(Posted 2013) [#11]
@Goodlookinguy: Thank you for your help!
I think that it is the limitation of the size of the method.
game.build\android\bin\classes\com\eme64\dingko001\c_TCode_String_Function.class
This is the file of my Class that contains the Method that created the error and it is 97.8 KB big. Now that I split the Method into 2 Parts it just works fine. This is a bit unsatisfying though. What purpose serves this limit? Memory-saving?

@SLotman: I have all that code and it runs just fine, never had any problem with it.
You are right, the strings do not have to be iniciated.
In the examples Admob is also started in the OnCreate, and when there is no Internet then it just does not show any Ads.
And also with Autofit, I just took it from the demo-code, and there it was also in the OnCreate.
But thanks anyway :)


Goodlookinguy(Posted 2013) [#12]
I looked up about the limitation and from Oracle's documentation it appears the limit is just some arbitrary value they chose. The same limitation is imposed on the number of interfaces a class can implement.

Edit: Nevermind, http://stackoverflow.com/questions/5689798/why-does-java-limit-the-size-of-a-method-to-65535-byte/5689834#5689834


eme64(Posted 2013) [#13]
It would be cool if there was some sort of Error-Detection for this problem, could save some hours. But it is now at least no Monkey-Bug. This limit may seem high, but if you have big tables (select-case-block) it is stupid to cut it into multiple methods. This is just spaghetti code in the end. And isn't the reason of our modern Languages to prevent this?


computercoder(Posted 2013) [#14]
I don't disagree about having some error handling capabilities.

In well written code, everything is broken down so the a higher level method relies on many smaller methods specialized at single tasks. It has a few different advantages in coding this way, one in particular is being able to read and follow the code easier. Maintaining the code is simpler to do as well, which in turn makes tracking bugs far easier in the long run. Each method you make is now callable by others, depending upon the scope you give it, and that allows you to make very re-usable code, and effectively you writen far less of it.

You can call it whatever you like, but if you design and structure your code right, its no where near spaghetti code. This is true of both procedural and object oriented code styles. We have MILLIONS of lines of code in the projects I work on at work. All of it is object oriented and we follow the practice I just described. When a bug appears within the code, we are able to locate the issue and have it rectified the same day (unless its a larger issue that needs some more time). The code is lightning fast as well.

In the end, its all bout how well you put your code together if its spaghetti code or its easy to read, understand, and maintain.


rIKmAN(Posted 2013) [#15]
This one, for sure must be on OnRender, and should be always called on every render frame.
SetVirtualDisplay Game.res_x, Game.res_y


If he is using autofit, then SetVirtualDisplay is called in OnCreate just once.
UpdateVirtualDisplay should be called in OnRender every frame, I think you may have mixed them up.


SLotman(Posted 2013) [#16]
@rlKmAn: probably, I automated everything here on my side so I only wrote this stuff ages ago :)

If I were to trace this bug, I would look at MonkeyGame.java, line 1499... since that's where the Java VM crashed. I still think it is something within OnCreate.


Samah(Posted 2013) [#17]
We had this problem at work too. Button/menu item definitions are stored in a huge HashMap so that user permissions can be applied to them. Some smart cookie thought it'd be a good idea to call map.put() 8000 times in the constructor. I changed it to read from a .dat file instead and all is well.