精华内容
下载资源
问答
  • chrome_v8_js引擎源码导读分析 第一章 v8 之整体流程 第二章 v8 之全局环境配置及初始化 2.1 全局模板 2.2 库函数 2.3 初始化 第三章 v8 之前端建立语法树 3.1 v8 编译中重要的类 3.2 compile之前的查找 ...
  • js代码解析的过程为编译成字节码后再加载字节码执行, ScriptCompiler::Compile()的过程是分为词法分析与语法分析,将js代码解析成AST树后就可以很顺利的转换成字节码。 本节先跳过复杂的编译过程看下执行逻辑。 0x...

    0x00 前言

    js代码解析的过程为编译成字节码后再加载字节码执行, ScriptCompiler::Compile()的过程是分为词法分析与语法分析,将js代码解析成AST树后就可以很顺利的转换成字节码。

    本节先跳过复杂的编译过程看下执行逻辑。

    0x01 调用栈

    Thread 1 "d8" hit Breakpoint 1, v8::Shell::ExecuteString (isolate=0x59000000000, source=..., name=..., print_result=v8::Shell::kNoPrintResult, 
        report_exceptions=v8::Shell::kReportExceptions, process_message_queue=v8::Shell::kProcessMessageQueue) at ../../src/d8/d8.cc:527
    527	    maybe_result = script->Run(realm);
    (gdb) s
    v8::Local<v8::Script>::operator-> (this=0x7fffffffd0a0) at ../../include/v8.h:213
    213	  V8_INLINE T* operator->() const { return val_; }
    (gdb) s
    v8::Script::Run (this=0x5555556c1b98, context=...) at ../../src/api/api.cc:2143
    2143	  auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
    (gdb) bt
    #0  v8::Script::Run (this=0x5555556c1b98, context=...) at ../../src/api/api.cc:2143
    #1  0x00005555555efd77 in v8::Shell::ExecuteString (isolate=0x59000000000, source=..., name=..., print_result=v8::Shell::kNoPrintResult, 
        report_exceptions=v8::Shell::kReportExceptions, process_message_queue=v8::Shell::kProcessMessageQueue) at ../../src/d8/d8.cc:527
    #2  0x00005555555fd57e in v8::SourceGroup::Execute (this=0x5555556542a8, isolate=0x59000000000) at ../../src/d8/d8.cc:2620
    #3  0x000055555560008b in v8::Shell::RunMain (isolate=0x59000000000, argc=2, argv=0x7fffffffdf38, last_run=true) at ../../src/d8/d8.cc:3100
    #4  0x00005555556013a6 in v8::Shell::Main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3741
    #5  0x00005555556016e2 in main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3777
    

    0x02 Script::Run函数

    MaybeLocal<Value> Script::Run(Local<Context> context) {
      auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
      //如果开启--trace-events-enabled选项的话,则初始化TraceEvent相关的对象,进行堆栈,性能相关
      //指标的跟踪,当然这里没有开启,可以忽略
      TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.Execute");
      //日志记录V8开始执行,声明布尔型变量has_pending_exception用于保存执行返回结果
      ENTER_V8(isolate, context, Script, Run, MaybeLocal<Value>(),
               InternalEscapableScope);
      //初始化直方图计时器
      i::HistogramTimerScope execute_timer(isolate->counters()->execute(), true);
      //初始化聚合直方图计时器
      i::AggregatingHistogramTimerScope timer(isolate->counters()->compile_lazy());
      //初始化计时器事件
      i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate);
      //初始化一个js函数句柄fun
      auto fun = i::Handle<i::JSFunction>::cast(Utils::OpenHandle(this));
      //初始化receiver
      i::Handle<i::Object> receiver = isolate->global_proxy();
      //初始化一个js变量用于保存js的执行结果
      Local<Value> result;
      //执行js代码
      has_pending_exception = !ToLocal<Value>(
          i::Execution::Call(isolate, fun, receiver, 0, nullptr), &result);
    
      RETURN_ON_FAILED_EXECUTION(Value);
      RETURN_ESCAPED(result);
    }
    

    TRACE_EVENT_CALL_STATS_SCOPED宏

    事件跟踪(trace event)是v8引擎的一个重要调试辅助的功能,事件有不同的分组(category),例如堆栈调用,函数执行时间等等。

    浏览器可以图形化这些事件日志,方便分析性能瓶颈。借用V8官网的一张图,同学们可以有个初步印象

    在这里插入图片描述
    回到源码上来,看下这个宏展开

    #define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name) \
      INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)
    

    继续展开

    #define INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED(isolate, category_group, name)  \
      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                      \
      v8::internal::tracing::CallStatsScopedTracer INTERNAL_TRACE_EVENT_UID(       \
          tracer);                                                                 \
      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {      \
        INTERNAL_TRACE_EVENT_UID(tracer)                                           \
            .Initialize(isolate, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
                        name);                                                     \
      }
    

    第一句

    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); 
    

    看下宏定义

    #define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)             \
      static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
      const uint8_t* INTERNAL_TRACE_EVENT_UID(category_group_enabled);         \
      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(                 \
          category_group, INTERNAL_TRACE_EVENT_UID(atomic),                    \
          INTERNAL_TRACE_EVENT_UID(category_group_enabled));
    

    宏定义太多了,就不一一介绍了,这段翻译成人话如下:

    //初始化一个事件临时变量
    static v8::base::AtomicWord trace_event_unique_atomic2144 = 0;
    //声明事件指针,为啥没有赋值?
    const uint8_t* trace_event_unique_category_group_enabled2144;
    //这里赋了初值,通过原子操作,原子操作的主要主用是避免多线程中读写错乱的问题
    trace_event_unique_category_group_enabled2144 =  reinterpret_cast<const uint8_t*>(
    	v8::base::Relaxed_Load(&(trace_event_unique_atomic2144)))//判断事件指针 != NULL则进到block中执行
    if (!trace_event_unique_category_group_enabled2144) {
        //获取TraceEventHelper的函数句柄,给事件指针
    	trace_event_unique_category_group_enabled2144 = 
    		v8::internal::tracing::TraceEventHelper::GetTracingController(
    		)->GetCategoryGroupEnabled(trace_event_unique_category_group_enabled2144);
    	v8::base::Relaxed_Store(
    		&(trace_event_unique_atomic2144), 
    		(reinterpret_cast<v8::base::AtomicWord>(
    		trace_event_unique_category_group_enabled2144)));
    }
    

    第二句

      v8::internal::tracing::CallStatsScopedTracer INTERNAL_TRACE_EVENT_UID(       \
          tracer);                                                                 \
    

    展开后

    v8::internal::tracing::CallStatsScopedTracer trace_event_unique_tracer2144;
    

    声明了一个CallStatsScopedTracer类型的scope状态跟踪器。

    第三句

      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {      \
        INTERNAL_TRACE_EVENT_UID(tracer)                                           \
            .Initialize(isolate, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
                        name);                                                     \
      }
    

    展开后

    if( v8::base::Relaxed_Load(reinterpret_cast<const v8::base::Atomic8*>( 
          trace_event_unique_category_group_enabled2144))& (1|4) ){
       trace_event_unique_tracer2144.Initialize(isolate, trace_event_unique_category_group_enabled2144, name)
    }
    

    分解如下:
    INTERNAL_TRACE_EVENT_CALL_STATS_SCOPED中有一个if判断语句if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE())比较关键。
    看下if判断的内容

    #define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
      TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED() &                        \
          (kEnabledForRecording_CategoryGroupEnabledFlags |                  \
           kEnabledForEventCallback_CategoryGroupEnabledFlags)
    

    其中:
    kEnabledForRecording_CategoryGroupEnabledFlags = 1
    kEnabledForEventCallback_CategoryGroupEnabledFlags = 4
    继续展开前面的宏TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED()

    #define TRACE_EVENT_API_LOAD_CATEGORY_GROUP_ENABLED()                \
      v8::base::Relaxed_Load(reinterpret_cast<const v8::base::Atomic8*>( \
          INTERNAL_TRACE_EVENT_UID(category_group_enabled)))
    

    INTERNAL_TRACE_EVENT_UID宏的用处是:创建临时变量降低指令开销。这个变量名是由name_prefix和入口代码行号拼接组成的唯一名称,可以有效的避免冲突。

    P.S. 说是降低指令开销,但完全想不出来降低什么了?你人工命名也不会多一条指令,最大的好处就是不用费脑想变量名了而已。
    看看这组宏:

    #define INTERNAL_TRACE_EVENT_UID3(a, b) trace_event_unique_##a##b
    #define INTERNAL_TRACE_EVENT_UID2(a, b) INTERNAL_TRACE_EVENT_UID3(a, b)
    #define INTERNAL_TRACE_EVENT_UID(name_prefix) \
      INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
    

    拼接后的函数调用栈如下:

    (gdb) bt
    #0  v8::base::Relaxed_Load (ptr=0x7ffff7fb3b08 <v8::Script::Run(v8::Local<v8::Context>)::trace_event_unique_atomic2144>)
        at ../../src/base/atomicops_internals_portable.h:199
    #1  0x00007ffff66aafab in v8::Script::Run (this=0x5555556c1b98, context=...) at ../../src/api/api.cc:2144
    #2  0x00005555555efd77 in v8::Shell::ExecuteString (isolate=0x167c00000000, source=..., name=..., print_result=v8::Shell::kNoPrintResult, 
        report_exceptions=v8::Shell::kReportExceptions, process_message_queue=v8::Shell::kProcessMessageQueue) at ../../src/d8/d8.cc:527
    #3  0x00005555555fd57e in v8::SourceGroup::Execute (this=0x5555556542a8, isolate=0x167c00000000) at ../../src/d8/d8.cc:2620
    #4  0x000055555560008b in v8::Shell::RunMain (isolate=0x167c00000000, argc=2, argv=0x7fffffffdf38, last_run=true) at ../../src/d8/d8.cc:3100
    #5  0x00005555556013a6 in v8::Shell::Main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3741
    #6  0x00005555556016e2 in main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3777
    

    trace_event_unique_atomic2144确实是由固定字符串trace_event_unique_+name_prefix字符串atomic 和frame 1中的行号2144组成。

    TRACE EVENT宏小结

    主要用于事件追踪的注册,增加了多线程安全的原子操作保护。不是LZ关心的主要问题,不关心的同学也可以忽略掉。

    0x03 小结

    1. 执行js前增加trace event和计时器帮助性能优化
    2. 用了很多宏
    展开全文
  • d8自己封装了一个js代码执行器,上一篇我们的代码执行到options.isolate_sources[0].Execute(isolate,本文将做进一步分析。 0x01 调用栈 #0 v8::SourceGroup::Execute (this=0x5555556542a8, isolate=0x1e9d...

    0x00 前言

    d8自己封装了一个js代码执行器,上一篇我们的代码执行到options.isolate_sources[0].Execute(isolate,本文将做进一步分析。

    0x01 调用栈

    #0  v8::SourceGroup::Execute (this=0x5555556542a8, isolate=0x1e9d00000000) at ../../src/d8/d8.cc:2567
    #1  0x000055555560008b in v8::Shell::RunMain (isolate=0x1e9d00000000, argc=2, argv=0x7fffffffdf38, last_run=true) at ../../src/d8/d8.cc:3100
    #2  0x00005555556013a6 in v8::Shell::Main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3741
    #3  0x00005555556016e2 in main (argc=2, argv=0x7fffffffdf38) at ../../src/d8/d8.cc:3777
    

    0x02 SourceGroup::Execute函数

    bool SourceGroup::Execute(Isolate* isolate) {
      bool success = true;
      for (int i = begin_offset_; i < end_offset_; ++i) {
        const char* arg = argv_[i];
        //解析-e参数,d8需要执行一段js代码字符串的话,走这个条件分支
        if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
          // Execute argument given to -e option directly.
          //创建作用域
          HandleScope handle_scope(isolate);
          //创建匿名文件名
          Local<String> file_name =
              String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
                  .ToLocalChecked();
          //读取js代码
          Local<String> source =
              String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
                  .ToLocalChecked();
          Shell::set_script_executed();
          //执行js代码字符串
          if (!Shell::ExecuteString(isolate, source, file_name,
                                    Shell::kNoPrintResult, Shell::kReportExceptions,
                                    Shell::kNoProcessMessageQueue)) {
            success = false;
            break;
          }
          ++i;
          continue;
          //判断是否为js的module文件,规则后缀名必须为.mjs与--module参数连用
        } else if (ends_with(arg, ".mjs")) {
          Shell::set_script_executed();
          if (!Shell::ExecuteModule(isolate, arg)) {
            success = false;
            break;
          }
          continue;
          // 判断是否为module执行模式
        } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
          // Treat the next file as a module.
          arg = argv_[++i];
          Shell::set_script_executed();
          if (!Shell::ExecuteModule(isolate, arg)) {
            success = false;
            break;
          }
          continue;
        } else if (arg[0] == '-') {
          // Ignore other options. They have been parsed already.
          continue;
        }
    	//LZ这里的执行命令为d8 test.js,所以前面的逻辑都会跳过,真正的入口位置在这里
        // Use all other arguments as names of files to load and run.
        //定义作用域
        HandleScope handle_scope(isolate);
        //创建文件名字符串
        Local<String> file_name =
            String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
                .ToLocalChecked();
        //从文件中读取文件内容
        Local<String> source = ReadFile(isolate, arg);
        if (source.IsEmpty()) {
          printf("Error reading '%s'\n", arg);
          base::OS::ExitProcess(1);
        }
        //设置执行状态为true,该静态函数在d8.h中定义
        Shell::set_script_executed();
        //执行js代码
        if (!Shell::ExecuteString(isolate, source, file_name, Shell::kNoPrintResult,
                                  Shell::kReportExceptions,
                                  Shell::kProcessMessageQueue)) {
          success = false;
          break;
        }
      }
      return success;
    }
    

    0x03 Shell::ExecuteString函数

    // Executes a string within the current v8 context.
    bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
                              Local<Value> name, PrintResult print_result,
                              ReportExceptions report_exceptions,
                              ProcessMessageQueue process_message_queue) {
      //i::FLAG_parse_only 为false
      if (i::FLAG_parse_only) {
        i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
        i::VMState<PARSER> state(i_isolate);
        i::Handle<i::String> str = Utils::OpenHandle(*(source));
    
        // Set up ParseInfo.
        i::ParseInfo parse_info(i_isolate);
        parse_info.set_toplevel();
        parse_info.set_allow_lazy_parsing();
        parse_info.set_language_mode(
            i::construct_language_mode(i::FLAG_use_strict));
        parse_info.set_script(
            parse_info.CreateScript(i_isolate, str, options.compile_options));
    
        if (!i::parsing::ParseProgram(&parse_info, i_isolate)) {
          fprintf(stderr, "Failed parsing\n");
          return false;
        }
        return true;
      }
    
      HandleScope handle_scope(isolate);
      TryCatch try_catch(isolate);
      try_catch.SetVerbose(true);
    
      MaybeLocal<Value> maybe_result;
      bool success = true;
      {
        //获取自定义数据,get后为null。
        PerIsolateData* data = PerIsolateData::Get(isolate);
        //创建realm变量
        Local<Context> realm =
            Local<Context>::New(isolate, data->realms_[data->realm_current_]);
        Context::Scope context_scope(realm);
        MaybeLocal<Script> maybe_script;
        //创建当前上下文context
        Local<Context> context(isolate->GetCurrentContext());
        //创建ScriptOrigin对象origin
        ScriptOrigin origin(name);
         //v8有code caching功能,输入的js代码第一次被编译后,会生成一份cache,再次运行这份js代码时,会优先加载cache,减少重复编译带来的开销。
    	//编译选项如果为ScriptCompiler::kConsumeCodeCache,则寻找cache并加载
        if (options.compile_options == ScriptCompiler::kConsumeCodeCache) {
         //根据js代码字符串搜索cache
          ScriptCompiler::CachedData* cached_code =
              LookupCodeCache(isolate, source);
          //如果cache不为空
          if (cached_code != nullptr) {
            ScriptCompiler::Source script_source(source, origin, cached_code);
            maybe_script = ScriptCompiler::Compile(context, &script_source,
                                                   options.compile_options);
            CHECK(!cached_code->rejected);
          } else {
            ScriptCompiler::Source script_source(source, origin);
            maybe_script = ScriptCompiler::Compile(
                context, &script_source, ScriptCompiler::kNoCompileOptions);
          }
          // options.stress_background_compile为true,则后台编译
        } else if (options.stress_background_compile) {
        // 启动一个后台线程用于编译js脚本,后台编译就是script streaming 的优化方式
        // 同code cache的地位一样重要。浏览器加载多个js脚本时,边下载边编译的过程称为script streaming
          // Start a background thread compiling the script.
          BackgroundCompileThread background_compile_thread(isolate, source);
          //检查线程是否已经就绪
          CHECK(background_compile_thread.Start());
    
          // In parallel, compile on the main thread to flush out any data races.
          {
            TryCatch ignore_try_catch(isolate);
            ScriptCompiler::Source script_source(source, origin);
            USE(ScriptCompiler::Compile(context, &script_source,
                                        ScriptCompiler::kNoCompileOptions));
          }
    
          // Join with background thread and finalize compilation.
          background_compile_thread.Join();
          maybe_script = v8::ScriptCompiler::Compile(
              context, background_compile_thread.streamed_source(), source, origin);
        } else {
          //没有任何优化的编译方式
          ScriptCompiler::Source script_source(source, origin);
          maybe_script = ScriptCompiler::Compile(context, &script_source,
                                                 options.compile_options);
        }
    	//定义script变量
        Local<Script> script;
        if (!maybe_script.ToLocal(&script)) {
          //打印编译过程中的所有报错
          // Print errors that happened during compilation.
          if (report_exceptions) ReportException(isolate, &try_catch);
          return false;
        }
    	//如果kProduceCache选项开启,则将cache落地。
        if (options.code_cache_options ==
            ShellOptions::CodeCacheOptions::kProduceCache) {
          // Serialize and store it in memory for the next execution.
          ScriptCompiler::CachedData* cached_data =
              ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
          StoreInCodeCache(isolate, source, cached_data);
          delete cached_data;
        }
        //【重点】运行js脚本
        maybe_result = script->Run(realm);
        //处理选项,如果是kProduceCacheAfterExecute,则运行后在落地cache
        if (options.code_cache_options ==
            ShellOptions::CodeCacheOptions::kProduceCacheAfterExecute) {
          // Serialize and store it in memory for the next execution.
          ScriptCompiler::CachedData* cached_data =
              ScriptCompiler::CreateCodeCache(script->GetUnboundScript());
          StoreInCodeCache(isolate, source, cached_data);
          delete cached_data;
        }
        if (process_message_queue && !EmptyMessageQueues(isolate)) success = false;
        data->realm_current_ = data->realm_switch_;
      }
      Local<Value> result;
      //读取结果数据
      if (!maybe_result.ToLocal(&result)) {
        DCHECK(try_catch.HasCaught());
        // Print errors that happened during execution.
        if (report_exceptions) ReportException(isolate, &try_catch);
        return false;
      }
      DCHECK(!try_catch.HasCaught());
      if (print_result) {
        //如果配置了test_shell选项,则把结果重定向到标准输出
        if (options.test_shell) {
          //如果结果格式未定义,需要Stringify和格式化
          if (!result->IsUndefined()) {
            // If all went well and the result wasn't undefined then print
            // the returned value.
            v8::String::Utf8Value str(isolate, result);
            fwrite(*str, sizeof(**str), str.length(), stdout);
            printf("\n");
          }
        } else {
          v8::String::Utf8Value str(isolate, Stringify(isolate, result));
          fwrite(*str, sizeof(**str), str.length(), stdout);
          printf("\n");
        }
      }
      return success;
    }
    

    0x04 小结

    Shell::ExecuteString函数说明了v8运行的大致流程,如果写demo可以参考这个函数。

    展开全文
  • 1 v8的对象是4字节对齐的,用地址的低两位出来标记对象的类型。 2 堆对象(HeapObject)是Object的子类。Object里面的很多方法都是用于堆对象。堆对象有自己的一套对象类型判断方式。每个堆对象有一个map属性,他...

    Object是所有js对象在c++层的基类。

    class Object BASE_EMBEDDED {
     public:
     
      inline bool IsSmi();
      inline bool IsHeapObject();
      inline bool IsHeapNumber();
      inline bool IsString();
      inline bool IsSeqString();
      inline bool IsAsciiString();
      inline bool IsTwoByteString();
      inline bool IsConsString();
      inline bool IsSlicedString();
      inline bool IsExternalString();
      inline bool IsExternalAsciiString();
      inline bool IsExternalTwoByteString();
      inline bool IsShortString();
      inline bool IsMediumString();
      inline bool IsLongString();
      inline bool IsSymbol();
      inline bool IsNumber();
      inline bool IsByteArray();
      inline bool IsFailure();
      inline bool IsRetryAfterGC();
      inline bool IsException();
      inline bool IsJSObject();
      inline bool IsMap();
      inline bool IsFixedArray();
      inline bool IsDescriptorArray();
      inline bool IsContext();
      inline bool IsGlobalContext();
      inline bool IsJSFunction();
      inline bool IsCode();
      inline bool IsOddball();
      inline bool IsSharedFunctionInfo();
      inline bool IsJSValue();
      inline bool IsProxy();
      inline bool IsBoolean();
      inline bool IsJSArray();
      inline bool IsHashTable();
      inline bool IsDictionary();
      inline bool IsSymbolTable();
      inline bool IsPrimitive();
      inline bool IsGlobalObject();
      inline bool IsJSGlobalObject();
      inline bool IsJSBuiltinsObject();
      inline bool IsUndetectableObject();
      inline bool IsAccessCheckNeeded();
    
      // Returns true if this object is an instance of the specified
      // function template.
      bool IsInstanceOf(FunctionTemplateInfo* type);
    
      inline bool IsStruct();
      inline bool IsAccessorInfo(); 
      inline bool IsAccessCheckInfo(); 
      inline bool IsInterceptorInfo(); 
      inline bool IsCallHandlerInfo(); 
      inline bool IsFunctionTemplateInfo(); 
      inline bool IsObjectTemplateInfo(); 
      inline bool IsSignatureInfo(); 
      inline bool IsTypeSwitchInfo(); 
      inline bool IsDebugInfo(); 
      inline bool IsBreakPointInfo(); 
      inline bool IsScript();
    
      // Oddball testing.
      INLINE(bool IsUndefined());
      INLINE(bool IsTheHole());
      INLINE(bool IsNull());
      INLINE(bool IsTrue());
      INLINE(bool IsFalse());
    
      // Extract the number.
      inline double Number();
    
      Object* ToObject();             // ECMA-262 9.9.
      Object* ToBoolean();            // ECMA-262 9.2.
    
      Object* ToObject(Context* global_context);
    
      inline Object* ToSmi();
    
      void Lookup(String* name, LookupResult* result);
    
      // Property access.
      inline Object* GetProperty(String* key);
      inline Object* GetProperty(String* key, PropertyAttributes* attributes);
      Object* GetPropertyWithReceiver(Object* receiver,String* key,PropertyAttributes* attributes);
      Object* GetProperty(Object* receiver,LookupResult* result,String* key,PropertyAttributes* attributes);
      Object* GetPropertyWithCallback(Object* receiver,Object* structure,String* name,Object* holder);
    
      inline Object* GetElement(uint32_t index);
      Object* GetElementWithReceiver(Object* receiver, uint32_t index);
    
      Object* GetPrototype();
    
      inline bool IsStringObjectWithCharacterAt(uint32_t index);
    
      static Object* cast(Object* value) { return value; }
    
      // 对象在内存的布局,基类没有属性,内存是0
      static const int kSize = 0;  // Object does not take up any space.
    
     private:
      // 禁止直接创建对象,复制函数,赋值函数
      DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
    };
    

    基类主要是提供一些公共的方式,比如判断类型,属性存取。类型转化。

    1 c++对象的类型
    1 v8的对象是4字节对齐的,用地址的低两位出来标记对象的类型。
    2 堆对象(HeapObject)是Object的子类。Object里面的很多方法都是用于堆对象。堆对象有自己的一套对象类型判断方式。每个堆对象有一个map属性,他记录了堆对象的类型type,大小size。
    1 type主要是用于记录c++对象的类型。
    2 有一些单例的map对象,也是用于判断c++对象的类型的。
    3 map的type属性的低八位是用来区分是不是字符串类型的。高位8位是1说明不是字符串,是0说明是字符串类型。低7位记录字符串的子类型。
    下面是定义。

    // 第7位(从0开始算)如果是1说明对象不是字符串类型,否则是 
    const uint32_t kIsNotStringMask = 0x80;
    const uint32_t kStringTag = 0x0;
    const uint32_t kNotStringTag = 0x80;
    
    // If bit 7 is clear, bits 5 and 6 are the string's size (short, medium, or
    // long).
    // 对于字符串类型,5,6两位标记字符串的类型,短,中等,长三种类型
    const uint32_t kStringSizeMask = 0x60;
    const uint32_t kShortStringTag = 0x0;
    const uint32_t kMediumStringTag = 0x20;
    const uint32_t kLongStringTag = 0x40;
    
    // If bit 7 is clear, bit 4 indicates that the string is a symbol (if set) or
    // not (if cleared).
    // 第四位标记字符串是不是symbol类型,1则表示是
    const uint32_t kIsSymbolMask = 0x10;
    const uint32_t kNotSymbolTag = 0x0;
    const uint32_t kSymbolTag = 0x10;
    
    // If bit 7 is clear, and the string representation is a sequential string,
    // then bit 3 indicates whether the string consists of two-byte characters or
    // one-byte characters.
    // 第三位表示字符串是单字节字符还是双字节字符组成的
    const uint32_t kStringEncodingMask = 0x8;
    const uint32_t kTwoByteStringTag = 0x0;
    const uint32_t kAsciiStringTag = 0x8;
    
    // If bit 7 is clear, the low-order 3 bits indicate the representation
    // of the string.
    // 第0,1,2位表示字符串类型,四种
    const uint32_t kStringRepresentationMask = 0x07;
    enum StringRepresentationTag {
      kSeqStringTag = 0x0,
      kConsStringTag = 0x1,
      kSlicedStringTag = 0x2,
      kExternalStringTag = 0x3
    };
    
    enum InstanceType {
      // 下面都是字符串类型,根据上面的定义,下面的tag标记在8比特上各有自己的位置范围,所以相与的结果不会一样
      SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
      MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
      LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
      SHORT_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
      MEDIUM_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
      LONG_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
      SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
      MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
      LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
      SHORT_CONS_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
      MEDIUM_CONS_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
      LONG_CONS_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
      SHORT_SLICED_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSlicedStringTag,
      MEDIUM_SLICED_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSlicedStringTag,
      LONG_SLICED_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSlicedStringTag,
      SHORT_SLICED_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
      MEDIUM_SLICED_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
      LONG_SLICED_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
      SHORT_EXTERNAL_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kExternalStringTag,
      MEDIUM_EXTERNAL_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kExternalStringTag,
      LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
      SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
      MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
      LONG_EXTERNAL_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
      SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
      MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
      LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
      SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
      MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
      LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
      SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
      MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
      LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
      SHORT_CONS_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kConsStringTag,
      MEDIUM_CONS_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kConsStringTag,
      LONG_CONS_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kConsStringTag,
      SHORT_SLICED_STRING_TYPE = kShortStringTag | kSlicedStringTag,
      MEDIUM_SLICED_STRING_TYPE = kMediumStringTag | kSlicedStringTag,
      LONG_SLICED_STRING_TYPE = kLongStringTag | kSlicedStringTag,
      SHORT_SLICED_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSlicedStringTag,
      MEDIUM_SLICED_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSlicedStringTag,
      LONG_SLICED_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSlicedStringTag,
      SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
      MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
      LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
      SHORT_EXTERNAL_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kExternalStringTag,
      MEDIUM_EXTERNAL_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kExternalStringTag,
      LONG_EXTERNAL_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kExternalStringTag,
      LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
      /*
        下面是所有类型都不属于字符串类型,kNotStringTag是128,即10000000,
        因为最高一位是0表示是字符串类型,所以10000000保证了大于所有字符串类型的值
      */
      MAP_TYPE = kNotStringTag,
      HEAP_NUMBER_TYPE,
      FIXED_ARRAY_TYPE,
      CODE_TYPE,
      ODDBALL_TYPE,
      PROXY_TYPE,
      BYTE_ARRAY_TYPE,
      FILLER_TYPE,
      SMI_TYPE,
    
      ACCESSOR_INFO_TYPE,
      ACCESS_CHECK_INFO_TYPE,
      INTERCEPTOR_INFO_TYPE,
      SHARED_FUNCTION_INFO_TYPE,
      CALL_HANDLER_INFO_TYPE,
      FUNCTION_TEMPLATE_INFO_TYPE,
      OBJECT_TEMPLATE_INFO_TYPE,
      SIGNATURE_INFO_TYPE,
      TYPE_SWITCH_INFO_TYPE,
      DEBUG_INFO_TYPE,
      BREAK_POINT_INFO_TYPE,
      SCRIPT_TYPE,
    
      JS_OBJECT_TYPE,
      JS_GLOBAL_OBJECT_TYPE,
      JS_BUILTINS_OBJECT_TYPE,
      JS_VALUE_TYPE,
      JS_ARRAY_TYPE,
    
      JS_FUNCTION_TYPE,
    
      // Pseudo-types
      FIRST_NONSTRING_TYPE = MAP_TYPE,
      FIRST_TYPE = 0x0,
      LAST_TYPE = JS_FUNCTION_TYPE,
      
      FIRST_JS_OBJECT_TYPE = JS_OBJECT_TYPE,
      LAST_JS_OBJECT_TYPE = JS_ARRAY_TYPE
    }
    

    示例图如下
    在这里插入图片描述
    我们对c++对象的类型大概有了一个印象,下面看一下Object类的定义。下面是几个宏,用来判断c++对象的类型的。

    #define HAS_SMI_TAG(value) ((reinterpret_cast<int>(value) & kSmiTagMask) == kSmiTag)
    
    #define HAS_FAILURE_TAG(value) ((reinterpret_cast<int>(value) & kFailureTagMask) == kFailureTag)
    
    #define HAS_HEAP_OBJECT_TAG(value) ((reinterpret_cast<int>(value) & kHeapObjectTagMask) == kHeapObjectTag
    

    下面是一些有代表性的isType函数的定义。

    // 地址的低位是否是0
    bool Object::IObject::isSmi() {
      return HAS_SMI_TAG(this);
    }
    
    // 低两位是01
    bool Object::IsHeapObject() {
      return HAS_HEAP_OBJECT_TAG(this);
    }
    
    // 类型判断,在map里标记
    bool Object::IsHeapNumber() {
      return Object::IsHeapObject()
        && HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE;
    }
    
    bool Object::IsString() {
      return Object::IsHeapObject()
        && HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE;
    }
    
    bool Object::IsSeqString() {
      return IsString()
        && (String::cast(this)->representation_tag() == kSeqStringTag);
    }
    
    bool Object::IsByteArray() {
      return Object::IsHeapObject()
        && HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE;
    }
    
    bool Object::IsJSObject() {
      return IsHeapObject()
        && HeapObject::cast(this)->map()->instance_type() >= JS_OBJECT_TYPE;
    }
    // 根据单例map对象判断类型
    bool Object::IsContext() {
      return Object::IsHeapObject()
        && (HeapObject::cast(this)->map() == Heap::context_map() ||
            HeapObject::cast(this)->map() == Heap::global_context_map());
    }
    
    bool Object::IsUndefined() {
      return this == Heap::undefined_value();
    }
    
    
    bool Object::IsTheHole() {
      return this == Heap::the_hole_value();
    }
    

    下面继续看其他函数的定义。

    1 解包对象里的数字。smi是小整形,在v8中表示整形。长度是31位。

    double Object::Number() {
      return IsSmi()
        ? static_cast<double>(reinterpret_cast<Smi*>(this)->value())
        : reinterpret_cast<HeapNumber*>(this)->value();
    }
    

    2 转成smi对象

    Object* Object::ToSmi() {
      // 已经是,直接返回
      if (IsSmi()) return this;
      // 是堆对象
      if (IsHeapNumber()) {
        double value = HeapNumber::cast(this)->value();
        // double to int类型
        int int_value = FastD2I(value);
        if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
          return Smi::FromInt(int_value);
        }
      }
      return Failure::Exception();
    }
    

    3 判断index是不是字符串的有效长度

    bool Object::IsStringObjectWithCharacterAt(uint32_t index) {
      if (!this->IsJSValue()) return false;
    
      JSValue* js_value = JSValue::cast(this);
      if (!js_value->value()->IsString()) return false;
    
      String* str = String::cast(js_value->value());
      if (index >= (uint32_t)str->length()) return false;
    
      return true;
    }
    

    4 参考js的IsInstanceOf。很多类型后面的时候分析。

    bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
      // js对象的基类
      if (!this->IsJSObject()) return false;
      
      Object* cons_obj = JSObject::cast(this)->map()->constructor();
      if (!cons_obj->IsJSFunction()) return false;
      JSFunction* fun = JSFunction::cast(cons_obj);
      
      for (Object* type = fun->shared()->function_data();type->IsFunctionTemplateInfo(); type = FunctionTemplateInfo::cast(type)->parent_template()) {
        if (type == expected) return true;
      }
      // Didn't find the required type in the inheritance chain.
      return false;
    }
    

    5 ToObject,其他类型转成对象类型。js的原生类型需要转成对象的时候。具体的在分析子类时再详细分析。

    static Object* CreateJSValue(JSFunction* constructor, Object* value) {
      // 分类一个以constructor为构造函数的对象
      Object* result = Heap::AllocateJSObject(constructor);
      if (result->IsFailure()) return result;
      JSValue::cast(result)->set_value(value);
      return result;
    }
    
    
    Object* Object::ToObject(Context* global_context) {
      if (IsNumber()) {
        return CreateJSValue(global_context->number_function(), this);
      } else if (IsBoolean()) {
        return CreateJSValue(global_context->boolean_function(), this);
      } else if (IsString()) {
        return CreateJSValue(global_context->string_function(), this);
      }
      ASSERT(IsJSObject());
      return this;
    }
    
    
    Object* Object::ToObject() {
      Context* global_context = Top::context()->global_context();
      if (IsJSObject()) {
        return this;
      } else if (IsNumber()) {
        return CreateJSValue(global_context->number_function(), this);
      } else if (IsBoolean()) {
        return CreateJSValue(global_context->boolean_function(), this);
      } else if (IsString()) {
        return CreateJSValue(global_context->string_function(), this);
      }
    
      // Throw a type error.
      return Failure::InternalError();
    }
    

    6 ToBoolean,判断js变量是true或false的时候使用。

    Object* Object::ToBoolean() {
      if (IsTrue()) return Heap::true_value();
      if (IsFalse()) return Heap::false_value();
      // 数字0是false
      if (IsSmi()) {
        return Heap::ToBoolean(Smi::cast(this)->value() != 0);
      }
      // null或undefined是false
      if (IsUndefined() || IsNull()) return Heap::false_value();
      // Undetectable object is false
      if (IsUndetectableObject()) {
        return Heap::false_value();
      }
      // 空字符串是false
      if (IsString()) {
        return Heap::ToBoolean(String::cast(this)->length() != 0);
      }
      // 
      if (IsHeapNumber()) {
        return HeapNumber::cast(this)->HeapNumberToBoolean();
      }
      return Heap::true_value();
    }
    

    7 属性查找,使用具体类型的查找函数

    void Object::Lookup(String* name, LookupResult* result) {
      if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
      Object* holder = NULL;
      Context* global_context = Top::context()->global_context();
      if (IsString()) {
        holder = global_context->string_function()->instance_prototype();
      } else if (IsNumber()) {
        holder = global_context->number_function()->instance_prototype();
      } else if (IsBoolean()) {
        holder = global_context->boolean_function()->instance_prototype();
      }
      ASSERT(holder != NULL);  // cannot handle null or undefined.
      JSObject::cast(holder)->Lookup(name, result);
    }
    

    8 查找原型对象

    Object* Object::GetPrototype() {
      // 对象的原型对象存在map对象里
      if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
      Context* context = Top::context()->global_context();
    
      if (IsNumber()) return context->number_function()->instance_prototype();
      if (IsString()) return context->string_function()->instance_prototype();
      if (IsBoolean()) {
        return context->boolean_function()->instance_prototype();
      } else {
        return Heap::null_value();
      }
    }
    

    还有几个属性查找的函数,依赖一些子类,分析完子类再分析。

    展开全文
  • 本文获取源码的前提是科学上网,请自行解决。 0x01 使用Git V8的Git仓库为 https://chromium.googlesource.com/v8/v8.git,同时在GitHub上还有个官方镜像: https://github.com/v8/v8. 不管是为了遵循主流思想在git.....

    0x00 前言

    编译过程主要参考V8官网提供的指引手册进行,有坑的话我会尽量说明。官方指引手册【传送门

    2019/12/02 更新
    原标题为《Ubuntu16下V8源码编译之XX》,V8引擎内容比较多,本来不想写源码分为这么大的标题。奈何想写的东西比预期多一点,所以开了个大坑,希望能一点点填上。

    本文获取源码的前提是科学上网,请自行解决。

    0x01 使用Git

    V8的Git仓库为 https://chromium.googlesource.com/v8/v8.git,同时在GitHub上还有个官方镜像: https://github.com/v8/v8.

    不管是为了遵循主流思想在github上建仓,还是为了向墙里劳动人民推广压榨相对剩余价值的生产工具。从github上clone代码还是比较方便的。

    但是官方提示,请不要直接git clone上面的两个地址。如果想构建V8,请使用depot_tools工具拉取代码,会比较稳妥。

    0x02 拉取代码

    1. 在Linux或者MacOS上,需要先安装Git和depot_tools。
      Windows,需要安装Visual Studio, Debugging tools for Windows和depot_tools(包括Git)

      本文只以linux为例

    $ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
    
    1. 添加depot_tools工具路径到环境变量PATH中
    $ export PATH=$PATH:/path/to/depot_tools
    
    1. 如果你从未用过git,可以使用下面命令配置全局变量。
    $ git config --global user.name "John Doe"
    $ git config --global user.email "jdoe@email.com"
    $ git config --global core.autocrlf false
    $ git config --global core.filemode false
    $ # and for fun!
    $ git config --global color.ui true
    
    1. 进入工作路径workspace, 使用depot_tools拉取V8源码
    cd ~/workspace
    fetch v8
    

    过程如下

    ~/workspace$ fetch v8                                           
    Running: gclient root                                                           
    WARNING: Your metrics.cfg file was invalid or nonexistent. A new one will be cre
    ated.                                                                           
    Running: gclient config --spec 'solutions = [                                   
      {                                                                             
        "url": "https://chromium.googlesource.com/v8/v8.git",                       
        "managed": False,                                                           
        "name": "v8",                                                               
        "deps_file": "DEPS",                                                        
        "custom_deps": {},                                                          
      },                                                                            
    ]                                                                               
    '                                                                               
    Running: gclient sync --with_branch_heads                                       
    1>________ running 'git -c core.deltaBaseCacheLimit=2g clone --no-checkout --pro
    gress https://chromium.googlesource.com/v8/v8.git /home/test/workspace/_
    gclient_v8_O1ff0_' in '/home/test/workspace'                            
    1>Cloning into '/home/test/workspace/_gclient_v8_O1ff0_'...             
    1>remote: Sending approximately 914.91 MiB ...                                  
    1>remote: Counting objects: 7660, done                                          
    1>remote: Total 722377 (delta 573877), reused 722377 (delta 573877)             
    1>Receiving objects: 100% (722377/722377), 914.54 MiB | 5.66 MiB/s, done.       
    1>Resolving deltas: 100% (573877/573877), done.                                 
    1>Checking connectivity... done.                                                
    1>Syncing projects:   0% ( 0/ 2)                                                
    [0:04:14] Still working on:                                                     
    [0:04:14]   v8                                                                  
    Syncing projects: 100% (27/27), done.  
    
    ...
    
    Downloading 1 files took 5.139851 second(s)                                     
    Downloading /home/test/workspace/v8/third_party/binutils/Linux_x64/binut
    ils.tar.bz2                                                                     
    Extracting /home/test/workspace/v8/third_party/binutils/Linux_x64/binuti
    ls.tar.bz2                                                                      
    Running hooks:  76% (19/25) clang                                               
    ________ running 'vpython v8/tools/clang/scripts/update.py' in '/home/test/workspace'                                                                   
    Downloading https://commondatastorage.googleapis.com/chromium-browser-clang/Linu
    x_x64/clang-n331734-e84b7a5f-1.tgz .......... Done.                             
    Hook 'vpython v8/tools/clang/scripts/update.py' took 10.88 secs                 
    Running hooks: 100% (25/25), done.                                              
    Running: git submodule foreach 'git config -f $toplevel/.git/config submodule.$n
    ame.ignore all'                                                                 
    Running: git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*'        
    Running: git config diff.ignoreSubmodules all 
    

    看下代码磁盘空间

    $ du v8 -hs
    3.3G v8
    $ du deport_tools -hs
    690M deport_tools
    

    0x03 使用分支和更新

    创建一条新的本地分支(推荐)

    git new-branch fix-bug-1234
    

    更新代码

    在当前分支更新可以使用git pull命令,如果不在分支上,git pull会失效,此时需要使用git fetch命令。

    git pull
    

    有时需要更新V8的依赖环境,需要使用glient命令

    gclient sync
    

    0x04 参考文献

    https://v8.dev/docs/source-code

    展开全文
  • V8引擎使用Ninja进行构建源码,GN是用来辅助生成Ninja配置文件的工具。 从源码构建V8需要三个步骤: 生成构建所需文件( generating build files) 编译(compiling) 运行测试用例(running tests) 官方提供两种...
  • JS引擎V8 Parser源码分析

    热门讨论 2012-05-07 13:06:56
    JS引擎V8 Parser源码分析
  • V8源码分析之d8源码注解(第五篇)

    千次阅读 2019-12-20 18:46:37
    0x00 前言 没了你,我颓废了自己。心里那些苦,都只哽在喉咙里,一想起来就泪如雨下。 ----王国维 ...0x00007ffff4a8ea44 in v8::base::LocalKeyToPthreadKey (local_key=32767) at ../../src/base...
  • 前面已经把V8源码download下来和build的过程都讲过了。这里不做过多赘述,只说说在win7下搭建环境与的的一些问题。 0x01 系统环境 名称 版本 位数 备注 操作系统 Windows 7 Professional 6.1.7601, Service...
  • V8源码编译出来的可执行程序名为d8。d8作为V8引擎在命令行中可以使用的交互shell存在。平常V8的shell是在浏览器中可以看到的。Google官方已经不记得d8这个名字的由来,但是做为"delveloper she...
  • GlobalHandles是实现v8中持久句柄功能的类。GlobalHandles主要是维护一个链表,每个节点维护堆对象的状态。我们先看看节点的定义。 class GlobalHandles::Node : public Malloced { public: void Initialize...
  • 我们通过 node --inspect-brk 来分别运行这两段代码,在代码运行的最开始和结束的时候分别task heap snapshot,分析对应的内存占用信息如下: 可以发现第二段代码的内存占用明显要小于第一段,那么问题就出现在这个...
  • Handle是使用v8的时候很重要的一个概念和类。他本质是堆对象的封装。我们通过Handle管理真正的对象,而不是直接操作对象。Handle在v8中有两个实现。一个是对外使用的一个是内部使用的。我们先看一下内部使用的。 1 ...
  • HandleScope是一个栈式的管理方式,每次定义一个HandleScope对象的时候,就会压栈一个结构。接下来定义的Handle类都是在栈顶的那个结构中分配的。然后析构的时候,...这就是v8中的HandleScope的大致原理。
  • v8里有smi保存整形,但是他只有31位,超过31位的就需要用HeapNumber。 // 存储了数字的堆对象 class HeapNumber: public HeapObject { public: inline double value(); inline void set_value(double value); ...
  • // 内存布局信息,v8不定义对象的属性,而是通过offset来定义每个属性的位置 static const int kMapOffset = Object : : kSize ; static const int kSize = kMapOffset + kPointerSize ; ...
  • SemiSpace的管理新生代内存的类,即我们常听到的from区和to区。from区和to区都由一个SemiSpace对象管理。SemiSpace只管理地址,不负责分配和释放...SemiSpace的功能比较简单,有些属性的使用后续用到的时候再分析

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,209
精华内容 2,483
关键字:

v8源码分析