blob: 5e09f406a21b42f3a10c805609a653d4508a94ed [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLanguagePch.h"
#include "shlwapi.h"
namespace Js {
uint64 StackTraceArguments::ObjectToTypeCode(Js::Var object)
{
switch(JavascriptOperators::GetTypeId(object))
{
case TypeIds_Null:
return nullValue;
case TypeIds_Undefined:
return undefinedValue;
case TypeIds_Boolean:
return booleanValue;
case TypeIds_String:
return stringValue;
case TypeIds_Symbol:
return symbolValue;
case TypeIds_Number:
if (Js::JavascriptNumber::IsNan(JavascriptNumber::GetValue(object)))
{
return nanValue;
}
else
{
return numberValue;
}
case TypeIds_Integer:
case TypeIds_Int64Number:
case TypeIds_UInt64Number:
return numberValue;
}
return objectValue;
}
JavascriptString *StackTraceArguments::TypeCodeToTypeName(unsigned typeCode, ScriptContext *scriptContext)
{
switch(typeCode)
{
case nullValue:
return scriptContext->GetLibrary()->GetNullDisplayString();
case undefinedValue:
return scriptContext->GetLibrary()->GetUndefinedDisplayString();
case booleanValue:
return scriptContext->GetLibrary()->GetBooleanTypeDisplayString();
case stringValue:
return scriptContext->GetLibrary()->GetStringTypeDisplayString();
case nanValue:
return scriptContext->GetLibrary()->GetNaNDisplayString();
case numberValue:
return scriptContext->GetLibrary()->GetNumberTypeDisplayString();
case symbolValue:
return scriptContext->GetLibrary()->GetSymbolTypeDisplayString();
case objectValue:
return scriptContext->GetLibrary()->GetObjectTypeDisplayString();
default:
AssertMsg(0, "Unknown type code");
return scriptContext->GetLibrary()->GetEmptyString();
}
}
void StackTraceArguments::Init(const JavascriptStackWalker &walker)
{
types = 0;
if (!walker.IsCallerGlobalFunction())
{
int64 numberOfArguments = walker.GetCallInfo()->Count;
if (numberOfArguments > 0) numberOfArguments --; // Don't consider 'this'
if (walker.GetCallInfo()->Flags & Js::CallFlags_ExtraArg)
{
Assert(numberOfArguments > 0 );
// skip the last FrameDisplay argument.
numberOfArguments--;
}
for (int64 j = 0; j < numberOfArguments && j < MaxNumberOfDisplayedArgumentsInStack; j ++)
{
types |= ObjectToTypeCode(walker.GetJavascriptArgs()[j]) << 3*j; // maximal code is 7, so we can use 3 bits to store it
}
if (numberOfArguments > MaxNumberOfDisplayedArgumentsInStack)
{
types |= fTooManyArgs; // two upper bits are flags
}
}
else
{
types |= fCallerIsGlobal; // two upper bits are flags
}
}
HRESULT StackTraceArguments::ToString(LPCWSTR functionName, Js::ScriptContext *scriptContext, _In_ LPCWSTR *outResult) const
{
HRESULT hr = S_OK;
uint64 argumentsTypes = types;
BEGIN_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT_NESTED
{
CompoundString *const stringBuilder = CompoundString::NewWithCharCapacity(40, scriptContext->GetLibrary());
stringBuilder->AppendCharsSz(functionName);
bool calleIsGlobalFunction = (argumentsTypes & fCallerIsGlobal) != 0;
bool toManyArgs = (argumentsTypes & fTooManyArgs) != 0;
argumentsTypes &= ~fCallerIsGlobal; // erase flags to prevent them from being treated as values
argumentsTypes &= ~fTooManyArgs;
if (!calleIsGlobalFunction)
{
stringBuilder->AppendChars(_u('('));
}
for (uint64 i = 0; i < MaxNumberOfDisplayedArgumentsInStack && argumentsTypes != 0; i ++)
{
if (i > 0)
{
stringBuilder->AppendChars(_u(", "));
}
stringBuilder->AppendChars(TypeCodeToTypeName(argumentsTypes & 7, scriptContext)); // we use 3 bits to store one code
argumentsTypes >>= 3;
}
if (toManyArgs)
{
stringBuilder->AppendChars(_u(", ..."));
}
if (!calleIsGlobalFunction)
{
stringBuilder->AppendChars(_u(')'));
}
*outResult = stringBuilder->GetString();
}
END_TRANSLATE_EXCEPTION_AND_ERROROBJECT_TO_HRESULT(hr);
return hr;
}
}