| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- /*
- * Copyright (C)2005-2019 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
- package haxe;
- import php.*;
- private typedef NativeTrace = NativeIndexedArray<NativeAssocArray<Dynamic>>;
- enum StackItem {
- CFunction;
- Module(m:String);
- FilePos(s:Null<StackItem>, file:String, line:Int, ?column:Null<Int>);
- Method(classname:Null<String>, method:String);
- LocalFunction(?v:Int);
- }
- class CallStack {
- /**
- 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}>;
- @:ifFeature("haxe.CallStack.exceptionStack")
- static var lastExceptionTrace:NativeTrace;
- public static function callStack():Array<StackItem> {
- return makeStack(Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS));
- }
- public static function exceptionStack():Array<StackItem> {
- return makeStack(lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace);
- }
- public static function toString(stack:Array<StackItem>) {
- var b = new StringBuf();
- for (s in stack) {
- b.add("\nCalled from ");
- itemToString(b, s);
- }
- return b.toString();
- }
- static function itemToString(b:StringBuf, s) {
- switch (s) {
- case CFunction:
- b.add("a C function");
- case Module(m):
- b.add("module ");
- b.add(m);
- case FilePos(s, file, line, _):
- if (s != null) {
- itemToString(b, s);
- b.add(" (");
- }
- b.add(file);
- b.add(" line ");
- b.add(line);
- if (s != null)
- b.add(")");
- case Method(cname, meth):
- b.add(cname == null ? "<unknown>" : cname);
- b.add(".");
- b.add(meth);
- case LocalFunction(n):
- b.add("local function");
- }
- }
- @:ifFeature("haxe.CallStack.exceptionStack")
- static function saveExceptionTrace(e:Throwable):Void {
- lastExceptionTrace = 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(lastExceptionTrace);
- if (!Global.isset(exceptionEntry['file']) || !Global.isset(currentTrace[-i]['file'])) {
- Global.array_pop(lastExceptionTrace);
- } else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) {
- Global.array_pop(lastExceptionTrace);
- } else {
- break;
- }
- }
- // Remove arguments from trace to avoid blocking some objects from GC
- var count = Global.count(lastExceptionTrace);
- for (i in 0...count) {
- lastExceptionTrace[i]['args'] = new NativeArray();
- }
- var thrownAt = new NativeAssocArray<Dynamic>();
- thrownAt['function'] = '';
- thrownAt['line'] = e.getLine();
- thrownAt['file'] = e.getFile();
- thrownAt['class'] = '';
- thrownAt['args'] = new NativeArray();
- Global.array_unshift(lastExceptionTrace, thrownAt);
- }
- static function makeStack(native:NativeTrace):Array<StackItem> {
- var result = [];
- var count = Global.count(native);
- for (i in 0...count) {
- 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;
- }
- }
|