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;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |