void
ThreadStackHelper::GetNativeStack(Stack& aStack)
{
#ifdef MOZ_THREADSTACKHELPER_NATIVE
  ThreadContext context;
  context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize);

  ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context);

  // Get pseudostack first and fill the thread context.
  GetStack(aStack);
  NS_ENSURE_TRUE_VOID(context.mValid);

  CodeModulesProvider modulesProvider;
  google_breakpad::BasicCodeModules modules(&modulesProvider);
  google_breakpad::BasicSourceLineResolver resolver;
  google_breakpad::StackFrameSymbolizer symbolizer(nullptr, &resolver);

#if defined(MOZ_THREADSTACKHELPER_X86)
  google_breakpad::StackwalkerX86 stackWalker(
    nullptr, &context.mContext, &context, &modules, &symbolizer);
#elif defined(MOZ_THREADSTACKHELPER_X64)
  google_breakpad::StackwalkerAMD64 stackWalker(
    nullptr, &context.mContext, &context, &modules, &symbolizer);
#elif defined(MOZ_THREADSTACKHELPER_ARM)
  google_breakpad::StackwalkerARM stackWalker(
    nullptr, &context.mContext, -1, &context, &modules, &symbolizer);
#else
  #error "Unsupported architecture"
#endif

  google_breakpad::CallStack callStack;
  std::vector<const google_breakpad::CodeModule*> modules_without_symbols;

  google_breakpad::Stackwalker::set_max_frames(ThreadContext::kMaxStackFrames);
  google_breakpad::Stackwalker::
    set_max_frames_scanned(ThreadContext::kMaxStackFrames);

  NS_ENSURE_TRUE_VOID(stackWalker.Walk(&callStack, &modules_without_symbols));

  const std::vector<google_breakpad::StackFrame*>& frames(*callStack.frames());
  for (intptr_t i = frames.size() - 1; i >= 0; i--) {
    const google_breakpad::StackFrame& frame = *frames[i];
    if (!frame.module) {
      continue;
    }
    const string& module = frame.module->code_file();
#if defined(XP_LINUX) || defined(XP_MACOSX)
    const char PATH_SEP = '/';
#elif defined(XP_WIN)
    const char PATH_SEP = '\\';
#endif
    const char* const module_basename = strrchr(module.c_str(), PATH_SEP);
    const char* const module_name = module_basename ?
                                    module_basename + 1 : module.c_str();

    char buffer[0x100];
    size_t len = 0;
    if (!frame.function_name.empty()) {
      len = PR_snprintf(buffer, sizeof(buffer), "%s:%s",
                        module_name, frame.function_name.c_str());
    } else {
      len = PR_snprintf(buffer, sizeof(buffer), "%s:0x%p",
                        module_name, (intptr_t)
                        (frame.instruction - frame.module->base_address()));
    }
    if (len) {
      aStack.AppendViaBuffer(buffer, len);
    }
  }
#endif // MOZ_THREADSTACKHELPER_NATIVE
}
    void JavascriptExternalFunction::PrepareExternalCall(Js::Arguments * args)
    {
        ScriptContext * scriptContext = this->type->GetScriptContext();
        Assert(!scriptContext->GetThreadContext()->IsDisableImplicitException());
        scriptContext->VerifyAlive();

        Assert(scriptContext->GetThreadContext()->IsScriptActive());

        if (args->Info.Count == 0)
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NullOrUndefined);
        }

        Var &thisVar = args->Values[0];

        Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(thisVar);

        this->callCount++;
        if (IS_JS_ETW(EventEnabledJSCRIPT_HOSTING_EXTERNAL_FUNCTION_CALL_START()))
        {
            JavascriptFunction* caller = nullptr;

            // Lot the caller function if the call count of the external function pass certain threshold (randomly pick 256)
            // we don't want to call stackwalk too often. The threshold can be adjusted as needed.
            if (callCount >= ETW_MIN_COUNT_FOR_CALLER && ((callCount % ETW_MIN_COUNT_FOR_CALLER) == 0))
            {
                Js::JavascriptStackWalker stackWalker(scriptContext);
                bool foundScriptCaller = false;
                while(stackWalker.GetCaller(&caller))
                {
                    if(caller != nullptr && Js::ScriptFunction::Is(caller))
                    {
                        foundScriptCaller = true;
                        break;
                    }
                }
                if(foundScriptCaller)
                {
                    Var sourceString = caller->EnsureSourceString();
                    Assert(JavascriptString::Is(sourceString));
                    const char16* callerString = Js::JavascriptString::FromVar(sourceString)->GetSz();
                    char16* outString = (char16*)callerString;
                    int length = 0;
                    if (wcschr(callerString, _u('\n')) != NULL || wcschr(callerString, _u('\n')) != NULL)
                    {
                        length = Js::JavascriptString::FromVar(sourceString)->GetLength();
                        outString = HeapNewArray(char16, length+1);
                        int j = 0;
                        for (int i = 0; i < length; i++)
                        {
                            if (callerString[i] != _u('\n') && callerString[i] != L'\r')
                            {
                                outString[j++] = callerString[i];
                            }
                        }
                        outString[j] = L'\0';
                    }
                    JS_ETW(EventWriteJSCRIPT_HOSTING_CALLER_TO_EXTERNAL(scriptContext, this, typeId, outString, callCount));
                    if (outString != callerString)
                    {
                        HeapDeleteArray(length+1, outString);
                    }
#if DBG_DUMP
                    if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostPhase))
                    {
                        Output::Print(_u("Large number of Call to trampoline: methodAddr= %p, Object typeid= %d, caller method= %s, callcount= %d\n"),
                            this, typeId, callerString, callCount);
                    }
#endif
                }
            }
            JS_ETW(EventWriteJSCRIPT_HOSTING_EXTERNAL_FUNCTION_CALL_START(scriptContext, this, typeId));
#if DBG_DUMP
            if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::HostPhase))
            {
                Output::Print(_u("Call to trampoline: methodAddr= %p, Object typeid= %d\n"), this, typeId);
            }
#endif
        }

        Js::RecyclableObject* directHostObject = nullptr;
        switch(typeId)
        {
        case TypeIds_Integer:
#if FLOATVAR
        case TypeIds_Number:
#endif // FLOATVAR
            Assert(!Js::RecyclableObject::Is(thisVar));
            break;
        default:
            {
                Assert(Js::RecyclableObject::Is(thisVar));

                ScriptContext* scriptContextThisVar = Js::RecyclableObject::FromVar(thisVar)->GetScriptContext();
                // We need to verify "this" pointer is active as well. The problem is that DOM prototype functions are
                // the same across multiple frames, and caller can do function.call(closedthis)
                Assert(!scriptContext->GetThreadContext()->IsDisableImplicitException());
                scriptContextThisVar->VerifyAlive();

                // translate direct host for fastDOM.
                switch(typeId)
                {
                case Js::TypeIds_GlobalObject:
                    {
                        Js::GlobalObject* srcGlobalObject = static_cast<Js::GlobalObject*>(thisVar);
                        directHostObject = srcGlobalObject->GetDirectHostObject();
                        // For jsrt, direct host object can be null. If thats the case don't change it.
                        if (directHostObject != nullptr)
                        {
                            thisVar = directHostObject;
                        }

                    }
                    break;
                case Js::TypeIds_Undefined:
                case Js::TypeIds_Null:
                    {
                        // Call to DOM function with this as "undefined" or "null"
                        // This should be converted to Global object
                        Js::GlobalObject* srcGlobalObject = scriptContextThisVar->GetGlobalObject() ;
                        directHostObject = srcGlobalObject->GetDirectHostObject();
                        // For jsrt, direct host object can be null. If thats the case don't change it.
                        if (directHostObject != nullptr)
                        {
                            thisVar = directHostObject;
                        }
                    }
                    break;
                }
            }
            break;
        }
    }