<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    《Chrome V8 源碼》43. Turbofan 源碼分析

    VSole2022-01-12 16:30:49

    介紹

    接上一篇文章繼續說,本文講解 Turbofan 的工作流程、梳理 PrepareJob、ExecuteJob 和 FinalizeJob 的主要功能以及重要數據結構。

    Turbofan 工作流程

    前文提到,Turbofan 分為 NotConcurrent 和 Concurrent 兩種工作方式,它們的區別是 NotConcurrent 立即啟動優化工作,而 Concurrent 把工作放進同步分發隊列。

    Concurrent 方式由 GetOptimizedCodeLater() 函數負責,其源碼如下:

    1.  bool GetOptimizedCodeLater(OptimizedCompilationJob* job, Isolate* isolate) {2.    OptimizedCompilationInfo* compilation_info = job->compilation_info();3.    if (!isolate->optimizing_compile_dispatcher()->IsQueueAvailable()) {4.      if (FLAG_trace_concurrent_recompilation) {5.  //省略................6.      }7.      return false;8.    }9.    if (isolate->heap()->HighMemoryPressure()) {10.      if (FLAG_trace_concurrent_recompilation) {11.  //省略................12.      }13.      return false;14.    }15.    TimerEventScope timer(isolate);16.    RuntimeCallTimerScope runtimeTimer(17.        isolate, RuntimeCallCounterId::kOptimizeConcurrentPrepare);18.    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),19.                 "V8.OptimizeConcurrentPrepare");20.    if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED) return false;21.    isolate->optimizing_compile_dispatcher()->QueueForOptimization(job);22.    if (FLAG_trace_concurrent_recompilation) {23.      PrintF("  ** Queued ");24.      compilation_info->closure()->ShortPrint();25.      PrintF(" for concurrent optimization.");26.    }27.    return true;28.  }
    

    上述代碼中,第 4-14 行檢測工作隊列和內存是否滿足要求,不滿足則停止優化編譯。停止優化編譯不影響當前 JavaScript 程序的運行,因為 JavaScript 程序正在被解釋執行。

    第 15-20 行統計 V8 運行信息,與優化編譯的功能無關;

    第 21 行把優化編譯工作 job 添加到工作隊列中,并返回結果 true。

    NotConcurrent 方式由 GetOptimizedCodeNow() 函數負責,其源碼如下:

    1.  bool GetOptimizedCodeNow(OptimizedCompilationJob* job, Isolate* isolate) {2.    TimerEventScope timer(isolate);3.    RuntimeCallTimerScope runtimeTimer(4.        isolate, RuntimeCallCounterId::kOptimizeNonConcurrent);5.    OptimizedCompilationInfo* compilation_info = job->compilation_info();6.    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),7.                 "V8.OptimizeNonConcurrent");8.    if (job->PrepareJob(isolate) != CompilationJob::SUCCEEDED ||9.        job->ExecuteJob(isolate->counters()->runtime_call_stats()) !=10.            CompilationJob::SUCCEEDED ||11.        job->FinalizeJob(isolate) != CompilationJob::SUCCEEDED) {12.      if (FLAG_trace_opt) {13.        CodeTracer::Scope scope(isolate->GetCodeTracer());14.        PrintF(scope.file(), "[aborted optimizing ");15.        compilation_info->closure()->ShortPrint(scope.file());16.        PrintF(scope.file(), " because: %s]",17.               GetBailoutReason(compilation_info->bailout_reason()));18.      }19.      return false;20.    }21.    // Success!22.    job->RecordCompilationStats(OptimizedCompilationJob::kSynchronous, isolate);23.    DCHECK(!isolate->has_pending_exception());24.    InsertCodeIntoOptimizedCodeCache(compilation_info);25.    job->RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, isolate);26.    return true;27.  }
    

    上述代碼中, 第 2-7 行統計 V8 運行信息,與優化編譯的功能無關;

    第 8-9 行完成優化編譯的所有工作,這些工作由 PrepareJob、ExecuteJob 以及 FinalizeJob 三個函數負責;

    第 10-25 行更新編譯狀態等信息并返回 true。優化編譯同步進行,也就意味著暫停解釋執行并等待優化編譯的結果。

    準備 PrepareJob

    源碼如下:

    1.  CompilationJob::Status OptimizedCompilationJob::PrepareJob(Isolate* isolate) {2.    DCHECK_EQ(ThreadId::Current(), isolate->thread_id());3.    DisallowJavascriptExecution no_js(isolate);4.    if (FLAG_trace_opt && compilation_info()->IsOptimizing()) {5.  //省略..............6.    }7.    // Delegate to the underlying implementation.8.    DCHECK_EQ(state(), State::kReadyToPrepare);9.    ScopedTimer t(&time_taken_to_prepare_);10.    return UpdateState(PrepareJobImpl(isolate), State::kReadyToExecute);11.  }
    

    上述代碼中,第 2-3 行做狀態檢測、第 4-6 行設置打印出輸信息;第 10 行 UpdateState 更新狀態信息,PrepareJobImpl 完成初始化工作,其源碼如下:

    1.  PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl(2.      Isolate* isolate) {3.    PipelineJobScope scope(&data_, isolate->counters()->runtime_call_stats());4.    if (compilation_info()->bytecode_array()->length() >5.        FLAG_max_optimized_bytecode_size) {6.      return AbortOptimization(BailoutReason::kFunctionTooBig);7.    }8.    if (!FLAG_always_opt) {9.      compilation_info()->MarkAsBailoutOnUninitialized();10.    }11.    if (FLAG_turbo_loop_peeling) {12.      compilation_info()->MarkAsLoopPeelingEnabled();13.    }14.    if (FLAG_turbo_inlining) {15.      compilation_info()->MarkAsInliningEnabled();16.    }17.    PoisoningMitigationLevel load_poisoning =18.        PoisoningMitigationLevel::kDontPoison;19.    if (FLAG_untrusted_code_mitigations) {20.      load_poisoning = PoisoningMitigationLevel::kPoisonCriticalOnly;21.    }22.    compilation_info()->SetPoisoningMitigationLevel(load_poisoning);23.    if (FLAG_turbo_allocation_folding) {24.      compilation_info()->MarkAsAllocationFoldingEnabled();25.    }26.    if (compilation_info()->closure()->raw_feedback_cell().map() ==27.            ReadOnlyRoots(isolate).one_closure_cell_map() &&28.        !compilation_info()->is_osr()) {29.      compilation_info()->MarkAsFunctionContextSpecializing();30.      data_.ChooseSpecializationContext();31.    }32.    if (compilation_info()->is_source_positions_enabled()) {33.      SharedFunctionInfo::EnsureSourcePositionsAvailable(34.          isolate, compilation_info()->shared_info());35.    }36.    data_.set_start_source_position(37.        compilation_info()->shared_info()->StartPosition());38.    linkage_ = new (compilation_info()->zone()) Linkage(39.        Linkage::ComputeIncoming(compilation_info()->zone(), compilation_info()));40.    if (compilation_info()->is_osr()) data_.InitializeOsrHelper();41.    Deoptimizer::EnsureCodeForDeoptimizationEntries(isolate);42.    pipeline_.Serialize();43.    if (!data_.broker()->is_concurrent_inlining()) {44.      if (!pipeline_.CreateGraph()) {45.        CHECK(!isolate->has_pending_exception());46.        return AbortOptimization(BailoutReason::kGraphBuildingFailed);47.      }48.    }49.    return SUCCEEDED;50.  }
    

    上述代碼中,第 4-7 行檢查 BytecodeArray 的長度是否超過最大長度限制;

    第 8-10 行檢查 always_optimization 使能標記,它的作用是 always try to optimize functions;

    第 11-25 行檢測 loop_peeling、inling、allocation_folding 使能標記,詳細說明參見 flag-definitions.h 文件;

    第 26-37 行設置 context、OSR、源碼信息;

    第 38 行創建編譯需要的 link 信息;

    第 44 行創建 V8.TFGraph,這之后不再需要 T了;

    編譯 ExecuteJob

    ExecuteJob() 中調用 ExecuteJobImpl() 來完成優化編譯的主體工作,其源碼如下:

    1.  PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl(2.    RuntimeCallStats* stats) {3.  PipelineJobScope scope(&data_, stats);4.  if (data_.broker()->is_concurrent_inlining()) {5.  //省略.....6.  }7.  bool success;8.   if (FLAG_turboprop) {9.     success = pipeline_.OptimizeGraphForMidTier(linkage_);10.   } else {11.     success = pipeline_.OptimizeGraph(linkage_);12.   }13.   if (!success) return FAILED;14.   pipeline_.AssembleCode(linkage_);15.   return SUCCEEDED;
    

    上述代碼的核心功能就兩個,一個基于圖的優化功能(OptimizeGraphForMidTier 和 OptimizeGraph),另一個匯編生成器(AssembleCode)。優化功能的源碼如下:

    bool PipelineImpl::OptimizeGraphForMidTier(Linkage* linkage) { Run(data->CreateTyper()); RunPrintAndVerify(TyperPhase::phase_name()); Run(); RunPrintAndVerify(TypedLoweringPhase::phase_name()); Run(); //省略..............}//分隔線....................bool PipelineImpl::OptimizeGraph(Linkage* linkage) {  PipelineData* data = this->data_;  data->BeginPhaseKind("V8.TFLowering");  Run(data->CreateTyper());  RunPrintAndVerify(TyperPhase::phase_name());  Run();  RunPrintAndVerify(TypedLoweringPhase::phase_name());  //省略..............}
    

    上述代碼中,每一個 Run 方法代表過了一種優化技術,每種優化技術的實現都有對應的數據結構,本文不做講解。

    匯編生成器(AssembleCode)的源碼如下:

    1.  void PipelineImpl::AssembleCode(Linkage* linkage,2.                                  std::unique_ptr<AssemblerBuffer> buffer) {3.    PipelineData* data = this->data_;4.    data->BeginPhaseKind("V8.TFCodeGeneration");5.    data->InitializeCodeGenerator(linkage, std::move(buffer));6.    Run<AssembleCodePhase>();7.  //省略.....8.  }9.  //分隔.................10.  CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(11.      Instruction* instr) {12.    switch (arch_opcode) {13.      case kArchCallCodeObject: {14.        if (HasImmediateInput(instr, 0)) {15.  //省略.......................16.        } else {17.          Register reg = i.InputRegister(0);18.          DCHECK_IMPLIES(19.              HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),20.              reg == kJavaScriptCallCodeStartRegister);21.          __ LoadCodeObjectEntry(reg, reg);22.          if (HasCallDescriptorFlag(instr, CallDescriptor::kRetpoline)) {23.            __ RetpolineCall(reg);24.          } else {25.            __ call(reg);26.          }  }27.        RecordCallPosition(instr);28.        frame_access_state()->ClearSPDelta();29.        break;30.      }31.      case kArchCallBuiltinPointer: {32.  //省略.......................33.        break;34.      }}35.  }
    

    上述第 5 行代碼初始 CodeGenerator,第 6 行代碼 Run() 方法最終會調用第 10 行 AssembleArchInstruction() 方法以完成匯編碼的生成。第 12-34 行代碼采用 switch-case 為每條操作碼(OPCODE)編寫不同的匯編碼生成規則。每條操作碼對應一個 case,這個 case 描繪了把操作碼轉換為匯編碼的規則。圖 1 給出了 AssembleArchInstruction 的調用堆棧。

    V8 中 OPCODE 分為兩類,一類是體系結構通用的操作碼(COMMON_ARCH_OPCODE_LIST),另一類是體系結構專用的操作碼(TARGET_ARCH_OPCODE_LIST),具體參見宏模板。

    收尾 FinalizeJob

    收尾工作由 FinalizeJobImpl() 負責,源碼如下:

    1.  PipelineCompilationJob::Status PipelineCompilationJob::FinalizeJobImpl(2.      Isolate* isolate) {3.  //省略.................4.    MaybeHandle<Code> maybe_code = pipeline_.FinalizeCode();5.    Handle<Code> code;6.    if (!maybe_code.ToHandle(&code)) {7.  //省略.................8.    }9.    if (!pipeline_.CommitDependencies(code)) {10.  //省略.................11.    }12.    compilation_info()->SetCode(code);13.    compilation_info()->native_context().AddOptimizedCode(*code);14.    RegisterWeakObjectsInOptimizedCode(code, isolate);15.    return SUCCEEDED;16.  }
    

    上述第 4 行代碼接收優化編譯的結果;第 6-8 行代碼優化編譯失敗并返回 false;第 9-11 行代碼重試優化編譯;第 12 行代碼將優化編譯結果存儲進 Cache,下次再優化該 SharedFunction 時將直接使用 Cache 結果。

    技術總結

    (1) —Trace-XXX 用于打印編譯狀態和結果,參見 d8 —help 或 flag-definitions.h;

    (2) 優化編譯的使能標記的定義在 flag-definitions.h 中;

    (3) On-Stack Replacement(OSR)是一種運行時替換函數的棧幀的方法。

    新文章介紹

    《Chrome V8 Bug》 系列文章即將上線。

    《Chrome V8 Bug》系列文章的目的是解釋漏洞的產生原因,并向你展示這些漏洞如何影響 V8 的正確性。其他的漏洞文章大多從安全研究的角度分析,講述如何設計與使用 PoC。而本系列文章是從源碼研究的角度來寫的,分析 PoC 在 V8 中的執行細節,講解為什么 Poc 要這樣設計。當然,學習 Poc 的設計與使用,是 V8 安全研究的很好的出發點,所以,對于希望深入學習 V8 源碼和 PoC 原理的人來說,本系列文章也是很有價值的介紹性讀物。

    本系列文章主要講解 https://bugs.chromium.org/p/v8/issues 的內容,每篇文章講解一個 issue。如果你有想學習的 issue 也可以告訴我,我會優先講解。

    代碼優化編譯程序
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    源碼分析1、LLVM編譯器簡介LLVM 命名最早源自于底層虛擬機的縮寫,由于命名帶來的混亂,LLVM就是該項目的全稱。LLVM 核心庫提供了與編譯器相關的支持,可以作為多種語言編譯器的后臺來使用。自那時以來,已經成長為LLVM的主干項目,由不同的子項目組成,其中許多是正在生產中使用的各種 商業和開源的項目,以及被廣泛用于學術研究。
    如果指定了一個類為final,則該類所有的方法都是final的。此舉能夠使性能平均提高50% 。因為對這些大對象的操作會造成系統大的開銷,稍有不慎,將會導致嚴重的后果。
    每次聊到代碼優化,都會有很多人說理論、架構、核心思路,其實我覺得代碼優化這事說簡單了很簡單,說復雜了吧它也有一定的難度,但是我覺得有一個良好的編碼習慣很重要,下面分享一下14個springboot項目中優化代碼的小技巧,讓代碼優化跟容易,就像完成一件小事。
    看雪論壇作者ID:wx_御史神風
    據外媒報道,韓國科技巨頭三星前不久發生了好幾起由ChatGPT引起的信息泄露事件,設備測量、產量數據、內部會議等機密內容都被傳輸到了海外。但從3月11日起,在認識到需要跟上技術進步后,三星的DS部門批準了使用GPT,并特別在公告中提醒員工 “注意公司內部信息安全,不要輸入敏感內容”。三星公司在知悉這些事件后,緊急采取了一系列緩解措施,例如將上傳內容限制在1024字節以內等。三星目前正向事故相關職員調查原委,必要時給予處罰。
    利用這一上下文,RASP能夠就應用安全做出明智決策,及時遏阻漏洞利用造成損害。因此,真正的RASP應該是零誤報和低延遲的,能夠即時提升性能。真正的RASP需要一系列不可改變的規則,這些規則靠上下文洞悉何時引入了新漏洞,并據此采取相應的措施。RASP出錯的三個方面1、吠犬問題:大多數警報都是誤報WAF的問題在于運行在網絡層,作為應用執行指標而言滯后了。相反,真正的RASP平臺在運行時執行實際保護。
    V8環境搭建
    2021-09-14 18:00:00
    本文是這個系列的第一篇,主要講解四部分內容。
    介紹實戰中由于各種情況,可能會對反序列化Payload的長度有所限制,因此研究反序列化Payload縮小技術是有意義且必要的本文以CommonsBeanutils1鏈為示例,
    本文講解 Turbofan 的工作流程、梳理 PrepareJob、ExecuteJob 和 FinalizeJob 的主要功能以及重要數據結構。
    此工具是因為看到了Dliv3師傅的Venom工具后,想著自己也寫一個屬于自己的多級代理工具,故而利用閑暇時間編寫的(是的,我又在重復造輪子), 在此感謝Dliv3師傅 XD。 廢話不多說,我把我的README先搬過來給大家瞅瞅 Stowaway是一個利用go語言編寫的多級代理工具用戶可使用此程序將外部流量通過多個節點代理至內網,并實現管理功能 此工具僅限于安全研究和教學,用戶承擔因使用此
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类