diff options
Diffstat (limited to '2023/10/05')
| -rw-r--r-- | 2023/10/05/v8中Number-toString-的实现/index.html | 2 | ||||
| -rw-r--r-- | 2023/10/05/v8中的Number-toString/index.html | 253 |
2 files changed, 254 insertions, 1 deletions
diff --git a/2023/10/05/v8中Number-toString-的实现/index.html b/2023/10/05/v8中Number-toString-的实现/index.html index ab166679..15ededb5 100644 --- a/2023/10/05/v8中Number-toString-的实现/index.html +++ b/2023/10/05/v8中Number-toString-的实现/index.html @@ -213,7 +213,7 @@ <div class="icon arrow-right"></div> <div class="post-link"> - <a href="/2023/09/28/A-Brief-History-of-Just-In-Time/">Next</a> + <a href="/2023/10/05/v8%E4%B8%AD%E7%9A%84Number-toString/">Next</a> </div> </div> diff --git a/2023/10/05/v8中的Number-toString/index.html b/2023/10/05/v8中的Number-toString/index.html new file mode 100644 index 00000000..b13f98eb --- /dev/null +++ b/2023/10/05/v8中的Number-toString/index.html @@ -0,0 +1,253 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="UTF-8"> +<meta name="viewport" + content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> +<meta http-equiv="X-UA-Compatible" content="ie=edge"> + + <meta name="author" content="韩暮秋"> + + + <meta name="subtitle" content="暮秋小屋"> + + + <meta name="description" content="这里是暮秋小屋,思念和灵感的寄存处"> + + + <meta name="keywords" content="韩暮秋,MuqiuHan"> + + + + +<title>v8中的Number.toString() | 暮秋小屋</title> + + + + + +<style> + @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&family=Roboto+Mono&display=swap'); +</style> + + + + <!-- stylesheets list from _config.yml --> + + <link rel="stylesheet" href="/css/style.css"> + + + + + + <!-- scripts list from _config.yml --> + + <script src="/js/frame.js"></script> + + + + + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> + + + + + + + + <meta name="generator" content="Hexo 6.3.0"></head> + <body> + <div class="mask-border"> + </div> + + <div class="wrapper"> + + <div class="header"> + <div class="flex-container"> + <div class="header-inner"> + <div class="site-brand-container"> + <a href="/"> + + 暮秋小屋 + + </a> + </div> + <div id="menu-btn" class="menu-btn" onclick="toggleMenu()"> + Menu + </div> + <nav class="site-nav"> + <ul class="menu-list"> + + + <li class="menu-item"> + <a href="/">主页</a> + </li> + + + + <li class="menu-item"> + <a href="/categories/gallery/">日记本</a> + </li> + + + + <li class="menu-item"> + <a href="/tags/Medicine/">医学</a> + </li> + + + + <li class="menu-item"> + <a href="/tags/Technique/">计算机科学</a> + </li> + + + + <li class="menu-item"> + <a href="/tags/Life/">生活</a> + </li> + + + + <li class="menu-item"> + <a href="/about">关于</a> + </li> + + + + </ul> + </nav> + </div> + </div> +</div> + + + <div class="main"> + <div class="flex-container"> + <article id="post"> + + + <div class="post-head"> + <div class="post-info"> + <div class="tag-list"> + + + <span class="post-tag"> + <a href="/tags/Technique/"> + Technique + </a> + </span> + + + </div> + <div class="post-title"> + + + v8中的Number.toString() + + + </div> + <span class="post-date"> + Oct 5, 2023 + </span> + </div> + <div class="post-img"> + + <div class="h-line-primary"></div> + + </div> +</div> + <div class="post-content"> + <p>这里讲一下JavaScript中<code>Number.toString()</code>的实现, 以V8为例。</p> +<ul> +<li><a target="_blank" rel="noopener" href="https://github.com/v8/v8/">The official mirror of the V8 Git repository</a></li> +</ul> +<p>在很多地方都能看到:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*isolate-><span class="built_in">factory</span>()-><span class="built_in">NumberToString</span>(value);</span><br></pre></td></tr></table></figure> +<p>例如 <a target="_blank" rel="noopener" href="https://github.com/v8/v8/blob/df99ca37a9d02a3318d3e5487c7803f6230b8f5f/src/builtins/builtins-number.cc#L140">/src/builtins/builtins-number.cc</a> 中。</p> +<p>下面看看<code>NumberToString</code>的定义, 应该是在 <a target="_blank" rel="noopener" href="https://github.com/v8/v8/blob/829e8d18d73e21807c78223b0cc107c76c80da27/src/heap/factory-base.cc#L963-L978">src/heap/factory-base.cc</a> 中:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> Impl></span><br><span class="line">Handle<String> FactoryBase<Impl>::<span class="built_in">NumberToString</span>(Handle<Object> number,</span><br><span class="line"> NumberCacheMode mode) {</span><br><span class="line"> <span class="built_in">SLOW_DCHECK</span>(<span class="built_in">IsNumber</span>(*number));</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">IsSmi</span>(*number)) <span class="keyword">return</span> <span class="built_in">SmiToString</span>(Smi::<span class="built_in">cast</span>(*number), mode);</span><br><span class="line"></span><br><span class="line"> <span class="type">double</span> double_value = Handle<HeapNumber>::<span class="built_in">cast</span>(number)-><span class="built_in">value</span>();</span><br><span class="line"> <span class="comment">// Try to canonicalize doubles.</span></span><br><span class="line"> <span class="type">int</span> smi_value;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">DoubleToSmiInteger</span>(double_value, &smi_value)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">SmiToString</span>(Smi::<span class="built_in">FromInt</span>(smi_value), mode);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">HeapNumberToString</span>(Handle<HeapNumber>::<span class="built_in">cast</span>(number), double_value,</span><br><span class="line"> mode);</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>可以看到这里调用了 <code>SmiToString</code>, 这里不往下翻这个函数的定义, 只需要知道Smi是什么即可。 Smi 是一种特殊的整数类型,它被用于表示较小的整数值,通常在 32 位系统中是 31 位有符号整数。Smi 类型的值存储在指针的低位,而指针的高位用于标记该值是一个 Smi 类型。<code>IsSmi</code> 函数会检查给定的值是否为 Smi 类型,如果是,则返回 true,否则返回 false。这个函数通常用于 V8 引擎内部的优化和性能优化。</p> +<p>所以<code>NumberToString</code>会判断number是否是一个smi, 如果是的话就调用SmiToString, 否则会尝试将其转换为double再去调用<code>DoubleToSmiInteger</code>, 将<code>DoubleToSmiInteger</code>的调用结果存在<code>smi_value</code>里面, 再通过调用<code>SmiToString</code>将<code>smi_value</code>转换为字符串。</p> +<p>如果这两条路都行不通的话,就直接调用<code>HeapNumberToString</code>了。</p> +<p><code>HeapNumberToString</code>的定义如下:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> Impl></span><br><span class="line">Handle<String> FactoryBase<Impl>::<span class="built_in">HeapNumberToString</span>(Handle<HeapNumber> number,</span><br><span class="line"> <span class="type">double</span> value,</span><br><span class="line"> NumberCacheMode mode) {</span><br><span class="line"> <span class="type">int</span> hash = mode == NumberCacheMode::kIgnore</span><br><span class="line"> ? <span class="number">0</span></span><br><span class="line"> : <span class="built_in">impl</span>()-><span class="built_in">NumberToStringCacheHash</span>(value);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (mode == NumberCacheMode::kBoth) {</span><br><span class="line"> Handle<Object> cached = <span class="built_in">impl</span>()-><span class="built_in">NumberToStringCacheGet</span>(*number, hash);</span><br><span class="line"> <span class="keyword">if</span> (!<span class="built_in">IsUndefined</span>(*cached, <span class="built_in">isolate</span>())) <span class="keyword">return</span> Handle<String>::<span class="built_in">cast</span>(cached);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> Handle<String> result;</span><br><span class="line"> <span class="keyword">if</span> (value == <span class="number">0</span>) {</span><br><span class="line"> result = <span class="built_in">zero_string</span>();</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (std::<span class="built_in">isnan</span>(value)) {</span><br><span class="line"> result = <span class="built_in">NaN_string</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="type">char</span> arr[kNumberToStringBufferSize];</span><br><span class="line"> <span class="function">base::Vector<<span class="type">char</span>> <span class="title">buffer</span><span class="params">(arr, arraysize(arr))</span></span>;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span>* string = <span class="built_in">DoubleToCString</span>(value, buffer);</span><br><span class="line"> result = <span class="built_in">CharToString</span>(<span class="keyword">this</span>, string, mode);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (mode != NumberCacheMode::kIgnore) {</span><br><span class="line"> <span class="built_in">impl</span>()-><span class="built_in">NumberToStringCacheSet</span>(number, hash, result);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>就是熟知的NaN, Undefined处理,重点在:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span> arr[kNumberToStringBufferSize];</span><br><span class="line"><span class="function">base::Vector<<span class="type">char</span>> <span class="title">buffer</span><span class="params">(arr, arraysize(arr))</span></span>;</span><br><span class="line"><span class="type">const</span> <span class="type">char</span>* string = <span class="built_in">DoubleToCString</span>(value, buffer);</span><br><span class="line">result = <span class="built_in">CharToString</span>(<span class="keyword">this</span>, string, mode);</span><br></pre></td></tr></table></figure> + +<p>这里调用了<code>DoubleToCString</code>, 其定义在 <a target="_blank" rel="noopener" href="https://github.com/v8/v8/blob/829e8d18d73e21807c78223b0cc107c76c80da27/src/numbers/conversions.cc#L1064-L1126">/src/numbers/conversions.cc</a> 中:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">const</span> <span class="type">char</span>* <span class="title">DoubleToCString</span><span class="params">(<span class="type">double</span> v, base::Vector<<span class="type">char</span>> buffer)</span> </span>{</span><br><span class="line"> <span class="keyword">switch</span> (FPCLASSIFY_NAMESPACE::<span class="built_in">fpclassify</span>(v)) {</span><br><span class="line"> <span class="keyword">case</span> FP_NAN:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"NaN"</span>;</span><br><span class="line"> <span class="keyword">case</span> FP_INFINITE:</span><br><span class="line"> <span class="keyword">return</span> (v < <span class="number">0.0</span> ? <span class="string">"-Infinity"</span> : <span class="string">"Infinity"</span>);</span><br><span class="line"> <span class="keyword">case</span> FP_ZERO:</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"0"</span>;</span><br><span class="line"> <span class="keyword">default</span>: {</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">IsInt32Double</span>(v)) {</span><br><span class="line"> <span class="comment">// This will trigger if v is -0 and -0.0 is stringified to "0".</span></span><br><span class="line"> <span class="comment">// (see ES section 7.1.12.1 #sec-tostring-applied-to-the-number-type)</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">IntToCString</span>(<span class="built_in">FastD2I</span>(v), buffer);</span><br><span class="line"> }</span><br><span class="line"> <span class="function">SimpleStringBuilder <span class="title">builder</span><span class="params">(buffer.begin(), buffer.length())</span></span>;</span><br><span class="line"> <span class="type">int</span> decimal_point;</span><br><span class="line"> <span class="type">int</span> sign;</span><br><span class="line"> <span class="type">const</span> <span class="type">int</span> kV8DtoaBufferCapacity = base::kBase10MaximalLength + <span class="number">1</span>;</span><br><span class="line"> <span class="type">char</span> decimal_rep[kV8DtoaBufferCapacity];</span><br><span class="line"> <span class="type">int</span> length;</span><br><span class="line"></span><br><span class="line"> base::<span class="built_in">DoubleToAscii</span>(</span><br><span class="line"> v, base::DTOA_SHORTEST, <span class="number">0</span>,</span><br><span class="line"> base::<span class="built_in">Vector</span><<span class="type">char</span>>(decimal_rep, kV8DtoaBufferCapacity), &sign,</span><br><span class="line"> &length, &decimal_point);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (sign) builder.<span class="built_in">AddCharacter</span>(<span class="string">'-'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (length <= decimal_point && decimal_point <= <span class="number">21</span>) {</span><br><span class="line"> <span class="comment">// ECMA-262 section 9.8.1 step 6.</span></span><br><span class="line"> builder.<span class="built_in">AddString</span>(decimal_rep);</span><br><span class="line"> builder.<span class="built_in">AddPadding</span>(<span class="string">'0'</span>, decimal_point - length);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="number">0</span> < decimal_point && decimal_point <= <span class="number">21</span>) {</span><br><span class="line"> <span class="comment">// ECMA-262 section 9.8.1 step 7.</span></span><br><span class="line"> builder.<span class="built_in">AddSubstring</span>(decimal_rep, decimal_point);</span><br><span class="line"> builder.<span class="built_in">AddCharacter</span>(<span class="string">'.'</span>);</span><br><span class="line"> builder.<span class="built_in">AddString</span>(decimal_rep + decimal_point);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (decimal_point <= <span class="number">0</span> && decimal_point > <span class="number">-6</span>) {</span><br><span class="line"> <span class="comment">// ECMA-262 section 9.8.1 step 8.</span></span><br><span class="line"> builder.<span class="built_in">AddString</span>(<span class="string">"0."</span>);</span><br><span class="line"> builder.<span class="built_in">AddPadding</span>(<span class="string">'0'</span>, -decimal_point);</span><br><span class="line"> builder.<span class="built_in">AddString</span>(decimal_rep);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// ECMA-262 section 9.8.1 step 9 and 10 combined.</span></span><br><span class="line"> builder.<span class="built_in">AddCharacter</span>(decimal_rep[<span class="number">0</span>]);</span><br><span class="line"> <span class="keyword">if</span> (length != <span class="number">1</span>) {</span><br><span class="line"> builder.<span class="built_in">AddCharacter</span>(<span class="string">'.'</span>);</span><br><span class="line"> builder.<span class="built_in">AddString</span>(decimal_rep + <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> builder.<span class="built_in">AddCharacter</span>(<span class="string">'e'</span>);</span><br><span class="line"> builder.<span class="built_in">AddCharacter</span>((decimal_point >= <span class="number">0</span>) ? <span class="string">'+'</span> : <span class="string">'-'</span>);</span><br><span class="line"> <span class="type">int</span> exponent = decimal_point - <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (exponent < <span class="number">0</span>) exponent = -exponent;</span><br><span class="line"> builder.<span class="built_in">AddDecimalInteger</span>(exponent);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> builder.<span class="built_in">Finalize</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>不用过多解释, 已经很清晰了, <code>FastD2I</code> 就是 Fast Double to Integer的意思, 定义如下, 注释也很详尽:</p> +<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// The fast double-to-(unsigned-)int conversion routine does not guarantee</span></span><br><span class="line"><span class="comment">// rounding towards zero.</span></span><br><span class="line"><span class="comment">// The result is undefined if x is infinite or NaN, or if the rounded</span></span><br><span class="line"><span class="comment">// integer value is outside the range of type int.</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="type">int</span> <span class="title">FastD2I</span><span class="params">(<span class="type">double</span> x)</span> </span>{</span><br><span class="line"> <span class="built_in">DCHECK</span>(x <= INT_MAX);</span><br><span class="line"> <span class="built_in">DCHECK</span>(x >= INT_MIN);</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">static_cast</span><<span class="type">int32_t</span>>(x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>以上</p> + +</div> + +<script> + window.onload = detectors(); +</script> + <div class="post-footer"> + <div class="h-line-primary"></div> + <nav class="post-nav"> + <div class="prev-item"> + + <div class="icon arrow-left"></div> + <div class="post-link"> + <a href="/2023/10/05/v8%E4%B8%ADNumber-toString-%E7%9A%84%E5%AE%9E%E7%8E%B0/">Prev</a> + </div> + + </div> + <div class="next-item"> + + <div class="icon arrow-right"></div> + <div class="post-link"> + <a href="/2023/09/28/A-Brief-History-of-Just-In-Time/">Next</a> + </div> + + </div> + </nav> +</div> + + + <div class="post-comment"> + + + + + + + +</div> + + +</article> + </div> + </div> + + <div class="footer"> + <div class="flex-container"> + <div class="footer-text"> + + + | + + + 希望路过的人可以添点柴火让这里暖和点 + + </div> + </div> +</div> + + </div> + + + + + </body> +</html> |
