diff options
| author | muqiuhan <[email protected]> | 2025-09-09 06:17:00 +0000 |
|---|---|---|
| committer | muqiuhan <[email protected]> | 2025-09-09 06:17:00 +0000 |
| commit | d5de65fdb1802cdf498d65d93397f290813c377c (patch) | |
| tree | 92fe61a76d20d1203203665d4b48e7f151f088bd /2023/10/05 | |
| parent | 48efa2dfde7c263f84ee5bb0872747034908d607 (diff) | |
| download | blog-d5de65fdb1802cdf498d65d93397f290813c377c.tar.gz | |
deploy: 9665097f0fa0dae9f92123fac54d26c0818758a5
Diffstat (limited to '2023/10/05')
| -rw-r--r-- | 2023/10/05/v8中的Number-toString/index.html | 11 |
1 files changed, 3 insertions, 8 deletions
diff --git a/2023/10/05/v8中的Number-toString/index.html b/2023/10/05/v8中的Number-toString/index.html index a311d7b1..6279fcc4 100644 --- a/2023/10/05/v8中的Number-toString/index.html +++ b/2023/10/05/v8中的Number-toString/index.html @@ -198,25 +198,20 @@ </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> +<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> +<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> |
