115 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			115 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | package haxe; | ||
|  | 
 | ||
|  | import php.*; | ||
|  | import haxe.CallStack.StackItem; | ||
|  | 
 | ||
|  | private typedef NativeTrace = NativeIndexedArray<NativeAssocArray<Dynamic>>; | ||
|  | 
 | ||
|  | /** | ||
|  | 	Do not use manually. | ||
|  | **/ | ||
|  | @:dox(hide) | ||
|  | @:noCompletion | ||
|  | @:allow(haxe.Exception) | ||
|  | class NativeStackTrace { | ||
|  | 	/** | ||
|  | 		If defined this function will be used to transform call stack entries. | ||
|  | 		@param String - generated php file name. | ||
|  | 		@param Int - Line number in generated file. | ||
|  | 	**/ | ||
|  | 	static public var mapPosition:String->Int->Null<{?source:String, ?originalLine:Int}>; | ||
|  | 
 | ||
|  | 	static var lastExceptionTrace:Null<NativeTrace>; | ||
|  | 
 | ||
|  | 	@:ifFeature('haxe.NativeStackTrace.exceptionStack') | ||
|  | 	static public function saveStack(e:Throwable) { | ||
|  | 		var nativeTrace = e.getTrace(); | ||
|  | 
 | ||
|  | 		// Reduce exception stack to the place where exception was caught | ||
|  | 		var currentTrace = Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS); | ||
|  | 		var count = Global.count(currentTrace); | ||
|  | 
 | ||
|  | 		for (i in -(count - 1)...1) { | ||
|  | 			var exceptionEntry:NativeAssocArray<Dynamic> = Global.end(nativeTrace); | ||
|  | 
 | ||
|  | 			if (!Global.isset(exceptionEntry['file']) || !Global.isset(currentTrace[-i]['file'])) { | ||
|  | 				Global.array_pop(nativeTrace); | ||
|  | 			} else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) { | ||
|  | 				Global.array_pop(nativeTrace); | ||
|  | 			} else { | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// Remove arguments from trace to avoid blocking some objects from GC | ||
|  | 		var count = Global.count(nativeTrace); | ||
|  | 		for (i in 0...count) { | ||
|  | 			nativeTrace[i]['args'] = new NativeArray(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		lastExceptionTrace = complementTrace(nativeTrace, e); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static public inline function callStack():NativeTrace { | ||
|  | 		return Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static public function exceptionStack():NativeTrace { | ||
|  | 		return lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static public function toHaxe(native:NativeTrace, skip:Int = 0):Array<StackItem> { | ||
|  | 		var result = []; | ||
|  | 		var count = Global.count(native); | ||
|  | 
 | ||
|  | 		for (i in 0...count) { | ||
|  | 			if(skip > i) { | ||
|  | 				continue; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			var entry = native[i]; | ||
|  | 			var item = null; | ||
|  | 
 | ||
|  | 			if (i + 1 < count) { | ||
|  | 				var next = native[i + 1]; | ||
|  | 
 | ||
|  | 				if (!Global.isset(next['function'])) | ||
|  | 					next['function'] = ''; | ||
|  | 				if (!Global.isset(next['class'])) | ||
|  | 					next['class'] = ''; | ||
|  | 
 | ||
|  | 				if ((next['function'] : String).indexOf('{closure}') >= 0) { | ||
|  | 					item = LocalFunction(); | ||
|  | 				} else if (Global.strlen(next['class']) > 0 && Global.strlen(next['function']) > 0) { | ||
|  | 					var cls = Boot.getClassName(next['class']); | ||
|  | 					item = Method(cls, next['function']); | ||
|  | 				} | ||
|  | 			} | ||
|  | 			if (Global.isset(entry['file'])) { | ||
|  | 				if (mapPosition != null) { | ||
|  | 					var pos = mapPosition(entry['file'], entry['line']); | ||
|  | 					if (pos != null && pos.source != null && pos.originalLine != null) { | ||
|  | 						entry['file'] = pos.source; | ||
|  | 						entry['line'] = pos.originalLine; | ||
|  | 					} | ||
|  | 				} | ||
|  | 				result.push(FilePos(item, entry['file'], entry['line'])); | ||
|  | 			} else if (item != null) { | ||
|  | 				result.push(item); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return result; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function complementTrace(nativeTrace:NativeTrace, e:Throwable):NativeTrace { | ||
|  | 		var thrownAt = new NativeAssocArray<Dynamic>(); | ||
|  | 		thrownAt['function'] = ''; | ||
|  | 		thrownAt['line'] = e.getLine(); | ||
|  | 		thrownAt['file'] = e.getFile(); | ||
|  | 		thrownAt['class'] = ''; | ||
|  | 		thrownAt['args'] = new NativeArray(); | ||
|  | 		Global.array_unshift(nativeTrace, thrownAt); | ||
|  | 		return nativeTrace; | ||
|  | 	} | ||
|  | } |