Понимание Chrome V8 — Глава 24. Как V8 описывает вашу функцию JavaScript

Понимание Chrome V8 — Глава 24. Как V8 описывает вашу функцию JavaScript

25 октября 2022 г.

Добро пожаловать в другие главы Давайте разберемся с Chrome V8

Когда мы изучаем V8, SharedFunction и JSFunction являются двумя очень распространенными и важными терминами, которые могут запутать новичков. Так что же они? В чем разница между ними? В общем, основная роль ShardFunction — место, где закладываются байткоды, есть и другие штуки вроде батута, о которых я расскажу в дальнейшем. SharedFunction можно грубо представить как библиотеку DLL, которую можно вызывать где угодно. Компилятор компилирует функцию JavaScript в SharedFunction, а SharedFunction можно использовать где угодно, например, в DLL. По этой причине его имя Shared-function.

Грубо, JSFunction равна SharedFunction + контекст. Когда V8 собирается вызвать SharedFunction, V8 должен связать контекст с ShareFunction, связывание — это термин V8, который означает, что он связывает SharedFuncton и контекст вместе, а именно JSFunction. JSFunction – это исполняемый экземпляр, который может быть запущен интерпретатором V8.

1. Общая функция

Следующий код представляет собой класс SharedFucntion.

1.  // SharedFunctionInfo describes the JSFunction information that can be
2.  // shared by multiple instances of the function.
3.  class SharedFunctionInfo : public HeapObject {
4.  public:
5.  V8_EXPORT_PRIVATE Code GetCode() const;
6.  V8_EXPORT_PRIVATE static void SetScript(
7.      Handle<SharedFunctionInfo> shared, Handle<Object> script_object,
8.       int function_literal_id, bool reset_preparsed_scope_data = true);
9.   V8_EXPORT_PRIVATE int EndPosition() const;
10.    V8_EXPORT_PRIVATE int StartPosition() const;
11.    V8_EXPORT_PRIVATE void SetPosition(int start_position, int end_position);
12.    inline bool IsApiFunction() const;
13.    inline bool is_class_constructor() const;
14.    inline FunctionTemplateInfo get_api_func_data();
15.    inline void set_api_func_data(FunctionTemplateInfo data);
16.    inline bool HasBytecodeArray() const;
17.    inline BytecodeArray GetBytecodeArray() const;
18.    inline void set_bytecode_array(BytecodeArray bytecode);
19.    inline Code InterpreterTrampoline() const;
20.    inline bool HasInterpreterData() const;
21.    inline InterpreterData interpreter_data() const;
22.    inline void set_interpreter_data(InterpreterData interpreter_data);
23.    // builtin_id corresponds to the auto-generated Builtins::Name id.
24.    inline bool HasBuiltinId() const;
25.    inline int builtin_id() const;
26.    inline void set_builtin_id(int builtin_id);
27.    inline bool HasUncompiledData() const;
28.    inline UncompiledData uncompiled_data() const;
29.    inline void set_uncompiled_data(UncompiledData data);
30.    inline bool HasUncompiledDataWithPreparseData() const;
31.    inline UncompiledDataWithPreparseData uncompiled_data_with_preparse_data()
32.        const;
33.    inline void set_uncompiled_data_with_preparse_data(
34.        UncompiledDataWithPreparseData data);
35.    inline bool HasUncompiledDataWithoutPreparseData() const;
36.    inline LanguageMode language_mode() const;
37.    inline void set_language_mode(LanguageMode language_mode);
38.    DECL_PRIMITIVE_ACCESSORS(syntax_kind, FunctionSyntaxKind)
39.    inline bool is_wrapped() const;
40.    DECL_BOOLEAN_ACCESSORS(has_duplicate_parameters)
41.    DECL_BOOLEAN_ACCESSORS(native)
42.    DECL_BOOLEAN_ACCESSORS(is_asm_wasm_broken)
43.    DECL_BOOLEAN_ACCESSORS(name_should_print_as_anonymous)
44.    DECL_BOOLEAN_ACCESSORS(is_oneshot_iife)
45.    DECL_BOOLEAN_ACCESSORS(are_properties_final)
46.    DECL_BOOLEAN_ACCESSORS(is_safe_to_skip_arguments_adaptor)
47.    DECL_BOOLEAN_ACCESSORS(has_reported_binary_coverage)
48.    DECL_BOOLEAN_ACCESSORS(private_name_lookup_skips_outer_class)
49.    inline FunctionKind kind() const;
50.    DECL_INT_ACCESSORS(function_map_index)
51.    inline void clear_padding();
52.    inline void UpdateFunctionMapIndex();
53.    inline bool optimization_disabled() const;
54.    inline BailoutReason disable_optimization_reason() const;
55.    void DisableOptimization(BailoutReason reason);
56.    DECL_BOOLEAN_ACCESSORS(requires_instance_members_initializer)
57.    bool HasSourceCode() const;
58.    static Handle<Object> GetSourceCode(Handle<SharedFunctionInfo> shared);
59.    static Handle<Object> GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared);
60.    inline bool IsSubjectToDebugging();
61.    inline bool IsUserJavaScript();
62.    inline bool CanDiscardCompiled() const;
63.    void UpdateExpectedNofPropertiesFromEstimate(FunctionLiteral* literal);
64.    void UpdateAndFinalizeExpectedNofPropertiesFromEstimate(
65.        FunctionLiteral* literal);
66.    DECL_CAST(SharedFunctionInfo)
67.    // Constants.
68.    static const uint16_t kDontAdaptArgumentsSentinel = static_cast<uint16_t>(-1);
69.    static const int kMaximumFunctionTokenOffset = kMaxUInt16 - 1;
70.    static const uint16_t kFunctionTokenOutOfRange = static_cast<uint16_t>(-1);
71.    STATIC_ASSERT(kMaximumFunctionTokenOffset + 1 == kFunctionTokenOutOfRange);
72.    DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
73.                                  TORQUE_GENERATED_SHARED_FUNCTION_INFO_FIELDS)
74.//............omit..............
75.    };

Строки 1–2 комментируют, что SharedFunction может совместно использоваться несколькими экземплярами.

Здесь я приведу вам несколько важных элементов SharedFunction.

  • Строка 5, GetCode() возвращает код. Я хотел бы пролить больше света на то, что код является встроенным кодом, а не вашим исходным кодом JavaScript, встроенный код используется для создания пролога функции для запуска интерпретатора. Перед вызовом функции V8 необходимо построить стек вызовов и получить адрес первой инструкции, за все это отвечает встроенный код;
  • Строка 6, SetScript() устанавливает исходный код JavaScript в SharedFunction;
  • В строках 9–11 задается смещение, описывающее соответствующую позицию между байт-кодом и исходным кодом JavaScript;
  • Строки 12–15 описывают, является ли SharedFunction функцией API;
  • Строки 16–18, они получают и устанавливают массив байт-кода для SharedFunction;
  • Строка 19, это адрес InterpreterTrampoline, о котором мы будем говорить в будущем;
  • Строки 27–35 — причина оптимизации TurboFan. Следующий список является причиной оптимизации.

#define BAILOUT_MESSAGES_LIST(V)                                            
  V(kNoReason, "no reason")                                                 
                                                                            
  V(kBailedOutDueToDependencyChange, "Bailed out due to dependency change") 
  V(kCodeGenerationFailed, "Code generation failed")                        
  V(kCyclicObjectStateDetectedInEscapeAnalysis,                             
    "Cyclic object state detected by escape analysis")                      
  V(kFunctionBeingDebugged, "Function is being debugged")                   
  V(kGraphBuildingFailed, "Optimized graph construction failed")            
  V(kFunctionTooBig, "Function is too big to be optimized")                 
  V(kLiveEdit, "LiveEdit")                                                  
  V(kNativeFunctionLiteral, "Native function literal")                      
  V(kNotEnoughVirtualRegistersRegalloc,                                     
    "Not enough virtual registers (regalloc)")                              
  V(kOptimizationDisabled, "Optimization disabled")                         
  V(kNeverOptimize, "Optimization is always disabled")
  • Строки 36–37, установите режим строгости или неаккуратности;
  • Строки 40–48, определение макроса DECL_BOOLEAN_ACCESSORS приведено ниже:
#define DECL_PRIMITIVE_ACCESSORS(name, type) 
  inline type name() const;                  
  inline void set_##name(type value);

#define DECL_BOOLEAN_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, bool)
  • Строка 72 определяет структуру памяти SharedFunction. Ниже приведен исходный код, а на рисунке 1 показана структура памяти:
#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO) 
  enum {                                                       
    LIST_MACRO##_StartOffset = StartOffset - 1,                
    LIST_MACRO(DEFINE_ONE_FIELD_OFFSET)                        
  };
//==================omit===========================
#define TORQUE_GENERATED_SHARED_FUNCTION_INFO_FIELDS(V) 
V(kStartOfWeakFieldsOffset, 0) 
V(kFunctionDataOffset, kTaggedSize) 
V(kEndOfWeakFieldsOffset, 0) 
V(kStartOfStrongFieldsOffset, 0) 
V(kNameOrScopeInfoOffset, kTaggedSize) 
V(kOuterScopeInfoOrFeedbackMetadataOffset, kTaggedSize) 
V(kScriptOrDebugInfoOffset, kTaggedSize) 
V(kEndOfStrongFieldsOffset, 0) 
V(kLengthOffset, kUInt16Size) 
V(kFormalParameterCountOffset, kUInt16Size) 
V(kExpectedNofPropertiesOffset, kUInt16Size) 
V(kFunctionTokenOffsetOffset, kUInt16Size) 
V(kFlagsOffset, kInt32Size) 
V(kFunctionLiteralIdOffset, kInt32Size) 
V(kUniqueIdOffset, kInt32Size) 
V(kSize, 0) 
//==============omit====================
#define FLAGS_BIT_FIELDS(V, _)//see line 70 above

2. JSFunction

Функция NewFunctionFromSharedFunctionInfo считывает SharedFunction и создает соответствующую JSFunction. Ниже приведен исходный код:

1.  Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
2.      Handle<SharedFunctionInfo> info, Handle<Context> context,
3.      AllocationType allocation) {
4.    Handle<Map> initial_map(
5.        Map::cast(context->native_context().get(info->function_map_index())),
6.        isolate());
7.    return NewFunctionFromSharedFunctionInfo(initial_map, info, context,
8.                                             allocation);
9.  }
10.  //==============分隔线============
11.  Handle<JSFunction> Factory::NewFunction(Handle<Map> map,
12.                                          Handle<SharedFunctionInfo> info,
13.                                          Handle<Context> context,
14.                                          AllocationType allocation) {
15.    Handle<JSFunction> function(JSFunction::cast(New(map, allocation)),
16.                                isolate());
17.    function->initialize_properties(isolate());
18.    function->initialize_elements();
19.    function->set_shared(*info);
20.    function->set_code(info->GetCode());
21.    function->set_context(*context);
22.    function->set_raw_feedback_cell(*many_closures_cell());
23. //........omit...............
24.  }

В приведенном выше коде строка 7 вызывает функцию NewFunction().

Здесь я расскажу вам некоторые подробности о NewFunction.

  • Строки 17–18 описывают некоторые свойства и элементы, которых нет у SharedFunction.
  • Строка 21 — это связанный контекст, о котором я упоминал выше.
  • В строках 19–20 они устанавливают соответствующий код SharedFunction и Builtins в JSFunction.

Хорошо, SharedFunction может совместно использоваться несколькими экземплярами, а JSFunction является исполняемым экземпляром.

Хорошо, на этом мы закончили. Увидимся в следующий раз, будьте осторожны!

Пожалуйста, свяжитесь со мной, если у вас возникнут вопросы. WeChat: qq9123013 Электронная почта: v8blink@outlook.com

:::информация Также опубликовано здесь.

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE