UString FunctionExecutable::paramString() const { FunctionParameters& parameters = *m_parameters; UStringBuilder builder; for (size_t pos = 0; pos < parameters.size(); ++pos) { if (!builder.isEmpty()) builder.append(", "); builder.append(parameters[pos].ustring()); } return builder.toUString(); }
JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) { ExecState* exec = toJS(ctx); JSLock lock(exec); unsigned count = 0; UStringBuilder builder; CallFrame* callFrame = exec; UString functionName; if (exec->callee()) { if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) { functionName = asInternalFunction(exec->callee())->name(exec); builder.append("#0 "); builder.append(functionName); builder.append("() "); count++; } } while (true) { ASSERT(callFrame); int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; UString levelStr = UString::number(count); exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); if (function) functionName = asFunction(function)->name(exec); else { // Caller is unknown, but if frame is empty we should still add the frame, because // something called us, and gave us arguments. if (count) break; } unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; if (!builder.isEmpty()) builder.append("\n"); builder.append("#"); builder.append(levelStr); builder.append(" "); builder.append(functionName); builder.append("() at "); builder.append(urlString); builder.append(":"); builder.append(UString::number(lineNumber)); if (!function || ++count == maxStackSize) break; callFrame = callFrame->callerFrame(); } return OpaqueJSString::create(builder.toUString()).leakRef(); }