<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko"><generator uri="https://jekyllrb.com/" version="3.9.4">Jekyll</generator><link href="https://blog.seokho.dev/ko/atom.xml" rel="self" type="application/atom+xml" /><link href="https://blog.seokho.dev/ko/" rel="alternate" type="text/html" hreflang="ko" /><updated>2025-10-08T12:18:59+00:00</updated><id>https://blog.seokho.dev/ko/</id><title type="html">Seokho’s blog</title><subtitle>Development and Tech blog</subtitle><author><name>Seokho Song</name><email>me@seokho.dev</email></author><entry><title type="html">디버깅 노트 — pdf.js 폰트 버그로 Chromium 이슈 등록하기</title><link href="https://blog.seokho.dev/ko/development/2025/08/27/debugging-note-pdfjs-fonts.html" rel="alternate" type="text/html" title="디버깅 노트 — pdf.js 폰트 버그로 Chromium 이슈 등록하기" /><published>2025-08-27T00:00:00+00:00</published><updated>2025-08-27T00:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2025/08/27/debugging-note-pdfjs-fonts</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2025/08/27/debugging-note-pdfjs-fonts.html">&lt;p&gt;최근에 회사 프론트엔드 제품에서 발견한 이슈를 chromium 이슈 트레커 crbug에 제보했다. 이 블로그 포스트에서는 브라우저 이슈라고 파악한 과정과 최소한의 재현 코드로 리포트한 방법을 간략히 공유하려고 한다.&lt;/p&gt;

&lt;p&gt;issue: &lt;a href=&quot;https://issues.chromium.org/u/1/issues/439716343&quot;&gt;https://issues.chromium.org/u/1/issues/439716343&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;얼마 전 CS팀에서 일부 사용자들이 Android 기기에서 PDF를 볼 때 텍스트가 깨진다고 공유했다.&lt;/p&gt;

&lt;p&gt;ANDROID:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/android-pdfjs-issue.png&quot; alt=&quot;android-pdfjs-issue&quot; /&gt;&lt;/p&gt;

&lt;p&gt;iOS 시뮬레이터:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/ios-pdfjs.png&quot; alt=&quot;ios-pdfjs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PDF의 전체 내용은 공유할 수 없다.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;우리 제품은 &lt;a href=&quot;https://mozilla.github.io/pdf.js/&quot;&gt;pdf.js&lt;/a&gt;를 사용해서 PDF 바이너리를 렌더링하는데, 꽤 오래된 버전을 사용하고 있다. 처음에는 버전 관련 문제라 생각했다. 설령 버전 문제가 &lt;em&gt;맞다고&lt;/em&gt; 한다고 하더라도, 왜 Android에서만 문제가 나타날까?&lt;/p&gt;

&lt;p&gt;안드로이드에서만 발생하는 현상으로 이 문제는 브라우저 관련 이슈라고 의심하기 시작했다. 하지만 이를 확인하려면 여러 레이어를 거쳐 어느 레이어에서 문제가 발생하는지 파악해야 한다. 지난 몇 년간 브라우저 프로젝트에 기여한 경험상, 최소한의 재현 코드(즉, 버그를 재현하는 기본 코드)가 있으면 조사하고 수정할 컴포넌트를 찾는 데 &lt;em&gt;상당히&lt;/em&gt; 도움이 된다.&lt;/p&gt;

&lt;p&gt;디버깅을 시작할 때, 어떤 폰트가 문제를 일으키는지 파악해야 했다.&lt;/p&gt;

&lt;p&gt;pdf.js의 텍스트 렌더링 코드에 로깅을 추가했다.&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gi&quot;&gt;+
&lt;/span&gt;      if (!fontObj) {
        throw new Error(`Can't find font for ${fontRefName}`);
      }
&lt;span class=&quot;p&quot;&gt;@@ -1321,6 +1323,8 @@&lt;/span&gt; var CanvasGraphics = (function CanvasGraphicsClosure() {

      var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
      this.ctx.font = rule;
&lt;span class=&quot;gi&quot;&gt;+
+      console.log('font changed: ', rule);
&lt;/span&gt;    },
    setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
      this.current.textRenderingMode = mode;
&lt;span class=&quot;p&quot;&gt;@@ -1483,6 +1487,7 @@&lt;/span&gt; var CanvasGraphics = (function CanvasGraphicsClosure() {
      ctx.lineWidth = lineWidth;

      var x = 0, i;
&lt;span class=&quot;gi&quot;&gt;+      console.log('drawing ',glyphs.map(g=&amp;gt;g.fontChar).join(''));
&lt;/span&gt;      for (i = 0; i &amp;lt; glyphsLength; ++i) {
        var glyph = glyphs[i];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;출력 예시:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;canvas.js:1327 font changed:  normal normal 16px &quot;g_d0_f2&quot;, sans-serif
canvas.js:1490 drawing  Hence,recordingandcompilingatrace
canvas.js:1327 font changed:  normal normal 16px &quot;g_d0_f10&quot;, sans-serif
canvas.js:1490 drawing  speculates
canvas.js:1327 font changed:  normal normal 16px &quot;g_d0_f2&quot;, sans-serif
canvas.js:1490 drawing  thatthepathand
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;pdfjs가 여러 폰트 패밀리를 처리하고 있다는 것을 발견했다.
Canvas API의 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font&quot;&gt;context.font property&lt;/a&gt;를 사용한다. CSS 규칙과 동일하다.&lt;/p&gt;

&lt;p&gt;다음으로, 폰트 파일이 어디서 로드되는지 추적했다.&lt;/p&gt;

&lt;p&gt;보다시피, 폰트 파일은 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts&quot;&gt;document.fonts property&lt;/a&gt;를 통해 로드되며, 이를 통해 일반적인 방식으로 폰트 패밀리를 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;이제 pdfjs가 폰트를 어떻게 처리하는지 알게 되었다.&lt;/p&gt;

&lt;p&gt;그 다음 pdfjs가 PDF 바이너리에서 폰트를 파싱하고 로드하는 방식을 살펴봤다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PDF 바이너리 읽기&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/PostScript_fonts#CID&quot;&gt;CID fonts&lt;/a&gt; 파싱&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;CFF Parser: &lt;a href=&quot;https://github.com/mozilla/pdf.js/blob/master/src/core/cff_parser.js&quot;&gt;https://github.com/mozilla/pdf.js/blob/master/src/core/cff_parser.js&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;결과는 메타데이터와 Uint8Array 폰트 데이터다.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;그 다음 앞서 언급한 대로 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FontFace&quot;&gt;FontFace&lt;/a&gt;를 생성하고 document.fonts에 추가한다&lt;/p&gt;

        &lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nx&quot;&gt;addNativeFontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nativeFontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nativeFontFaces&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nativeFontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fonts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nativeFontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;참고: &lt;a href=&quot;https://github.com/mozilla/pdf.js/blob/dd560ee453c8189a9cb1ee1dea164ca1702ad020/src/display/font_loader.js#L48&quot;&gt;https://github.com/mozilla/pdf.js/blob/dd560ee453c8189a9cb1ee1dea164ca1702ad020/src/display/font_loader.js#L48&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Document/fonts&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;파싱 과정을 아래 코드를 집어넣어 마지막에 폰트 blob을 다운로드하도록 했다.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;detectFontType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromCharCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;h0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;wOFF&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;font/woff&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.woff&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;wOF2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;font/woff2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.woff2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;OTTO&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;font/otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// OpenType/CFF&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;h0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;font/ttf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.ttf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// TrueType/OpenType&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/octet-stream&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.bin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;downloadBlob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;detectFontType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;blob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Blob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mime&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createObjectURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;blob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;endsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ext&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;revokeObjectURL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nativeFontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;family&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g_d1_f5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;downloadBlob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 추출된 .otf 폰트 파일을 얻었다.&lt;/p&gt;

&lt;p&gt;이 .otf 파일들을 사용해서 최소한의 재현 코드를 만들었다:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width, initial-scale=1.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Canvas Font Test&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;20px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system-ui&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;-apple-system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sans-serif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;.canvas-container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;canvas&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#ccc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;#333&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Canvas Font Test&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;g_d1_f16.otf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas_f16&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;800&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;g_d1_f5.otf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas_f5&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;800&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;g_d1_f6.otf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas_f6&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;800&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;g_d1_f7.otf&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;canvas_f7&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;800&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Font configurations&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fontConfigs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;G_D1_F16&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g_d1_f16.otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;canvasId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;canvas_f16&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;G_D1_F5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g_d1_f5.otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;canvasId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;canvas_f5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;G_D1_F6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g_d1_f6.otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;canvasId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;canvas_f6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;G_D1_F7&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;g_d1_f7.otf&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;canvasId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;canvas_f7&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Load all fonts&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fontPromises&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fontConfigs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FontFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`url('./&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;')`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadedFont&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fonts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;loadedFont&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loadedFont&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Failed to load font &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loadedFonts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fontPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;loadedFonts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;canvasId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2d&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;16px sans-serif&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Error loading font: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;black&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;32px &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;The quick brown fox - ABC123&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;32px &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;다람쥐 헌 쳇바퀴에 타고파&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;32px &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1234567890 !@#$%^&amp;amp;*()&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;12px sans-serif&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillStyle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#666&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Font: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/reproduction.png&quot; alt=&quot;reproduction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이슈를 제보하고 chromium slack에 공유했다. 누군가가 이것이 폰트 컴포넌트나 SKIA와 관련이 있을 것 같다고 말해줬다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/slack.png&quot; alt=&quot;slack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그럼 다음은?&lt;/p&gt;

&lt;p&gt;지금은 적절한 엔지니어가 이 이슈를 담당하기를 기다리고 있다. 만약 한동안 할당되지 않는다면, 아마도 이 이슈 자체를 직접 더 깊이 파볼 계획이다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;업데이트&quot;&gt;업데이트!&lt;/h3&gt;

&lt;p&gt;Dominik 이 이슈를 가져갔다! googlefonts/fontations 에 이슈를 올렸다고 한다. M131 부터 발생한거로 추정된다고 한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/update.png&quot; alt=&quot;update&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;그리고-또-다른-업데이트&quot;&gt;그리고 또 다른 업데이트!&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/fixed.png&quot; alt=&quot;fixed&quot; /&gt;&lt;/p&gt;

&lt;p&gt;업스트림에서 문제가 수정되었다. 새로운 폰트 엔진(아마 M131에서 활성화된 것으로 보인다)에서 나온 버그였다.&lt;/p&gt;

&lt;p&gt;이번 수정은 캔버스 이슈뿐만 아니라 웹 플랫폼에서의 특정 폰트 렌더링 문제도 함께 해결한다는 점에서 의미가 크다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/font.png&quot; alt=&quot;font&quot; /&gt;&lt;/p&gt;

&lt;p&gt;문제가 있었던 PDF에서 이슈가 해결된 것을 확인했고, 10월 말에 릴리즈되는 M142에 포함되어 배포될 예정이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-08-27/release.png&quot; alt=&quot;release&quot; /&gt;&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="Frontend" /><category term="pdf" /><summary type="html">최근에 회사 프론트엔드 제품에서 발견한 이슈를 chromium 이슈 트레커 crbug에 제보했다. 이 블로그 포스트에서는 브라우저 이슈라고 파악한 과정과 최소한의 재현 코드로 리포트한 방법을 간략히 공유하려고 한다.</summary></entry><entry><title type="html">V8 기여 영역을 새로운 top tier 컴파일러 Turbolev 로 확장하기</title><link href="https://blog.seokho.dev/ko/development/2025/07/15/V8-Expanding-To-Turbolev.html" rel="alternate" type="text/html" title="V8 기여 영역을 새로운 top tier 컴파일러 Turbolev 로 확장하기" /><published>2025-07-15T00:00:00+00:00</published><updated>2025-07-15T00:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2025/07/15/V8-Expanding-To-Turbolev</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2025/07/15/V8-Expanding-To-Turbolev.html">&lt;p&gt;저는 최근들어 V8 기여 범위를 JS 를 구현하는 영역에서 더 낮은 레이어의 컴파일러 파이프라인으로 확장했습니다.&lt;/p&gt;

&lt;p&gt;이 파이프라인은 바이트코드를 받아 기계어 코드를 생성하거나, 다음 컴파일러를 위한 새로운 그래프를 생성하는 역할을 합니다. 이 파이프 라인은 각각 Maglev와 Turbolev라고 불립니다.&lt;/p&gt;

&lt;p&gt;이 글에서는 제가 &lt;strong&gt;어떻게 기여 영역을 확장했고, Turbolev 프로젝트에 어떤 기여&lt;/strong&gt;를 했는지 설명할 것 입니다.&lt;/p&gt;

&lt;h2 id=&quot;backgrounds&quot;&gt;Backgrounds&lt;/h2&gt;
&lt;h3 id=&quot;v8과-jit&quot;&gt;V8과 JIT&lt;/h3&gt;

&lt;p&gt;V8은 크롬, NodeJS, Deno 등 많은 곳에서 사용되는 자바스크립트 엔진입니다. V8은 multi-tiering JIT 컴파일러를 가지고 있습니다. Just-in-time, 즉 JIT 컴파일은 프로그램 실행 전이 아닌 실행 중에 코드를 실시간으로 컴파일하는 방식입니다. [FYI: &lt;a href=&quot;https://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;Wikipedia&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;예를 들어, 아래 코드는 바이트코드로 컴파일 되어 바이트 코드가 가상 머신에서 실행됩니다. 다시 말해 실제 기계어가 아니라는 뜻 입니다.&lt;/p&gt;

&lt;p&gt;Code:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bytecode:&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
devsdk@dave ~/workspace/chromium/v8/v8 % ./out/arm64.release/d8 ~/workspace/chromium/playground/add.js &lt;span class=&quot;nt&quot;&gt;--print-bytecode&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;generated bytecode &lt;span class=&quot;k&quot;&gt;for function&lt;/span&gt;:  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x2f3e0005d7cd &amp;lt;SharedFunctionInfo&amp;gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt;
Bytecode length: 28
Parameter count 1
Register count 4
Frame size 32
         0xaef00100084 @    0 : 13 00             LdaConstant &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0]
         0xaef00100086 @    2 : cf                Star1
         0xaef00100087 @    3 : 1b fe f7          Mov &amp;lt;closure&amp;gt;, r2
         0xaef0010008a @    6 : 6d 6f 01 f8 02    CallRuntime &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;DeclareGlobals], r1-r2
         0xaef0010008f @   11 : 23 01 00          LdaGlobal &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1], &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0]
         0xaef00100092 @   14 : cf                Star1
         0xaef00100093 @   15 : 0d 01             LdaSmi &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]
         0xaef00100095 @   17 : ce                Star2
         0xaef00100096 @   18 : 0d 02             LdaSmi &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2]
         0xaef00100098 @   20 : &lt;span class=&quot;nb&quot;&gt;cd                &lt;/span&gt;Star3
         0xaef00100099 @   21 : 6b f8 f7 f6 02    CallUndefinedReceiver2 r1, r2, r3, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2]
         0xaef0010009e @   26 : d0                Star0
         0xaef0010009f @   27 : b5                Return
Constant pool &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
0xaef0010004d: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;TrustedFixedArray]
 - map: 0x2f3e00000605 &amp;lt;Map&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;TRUSTED_FIXED_ARRAY_TYPE&lt;span class=&quot;o&quot;&gt;)&amp;gt;&lt;/span&gt;
 - length: 2
           0: 0x2f3e0005d81d &amp;lt;FixedArray[2]&amp;gt;
           1: 0x2f3e00003e8d &amp;lt;String[3]: &lt;span class=&quot;c&quot;&gt;#add&amp;gt;&lt;/span&gt;
Handler Table &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Source Position Table &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;generated bytecode &lt;span class=&quot;k&quot;&gt;for function&lt;/span&gt;: add &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x2f3e0005d82d &amp;lt;SharedFunctionInfo add&amp;gt;&lt;span class=&quot;o&quot;&gt;)]&lt;/span&gt;
Bytecode length: 6
Parameter count 3
Register count 0
Frame size 0
         0xaef001000c8 @    0 : 0b 04             Ldar a1
         0xaef001000ca @    2 : 3f 03 00          Add a0, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;0]
         0xaef001000cd @    5 : b5                Return
Constant pool &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Handler Table &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Source Position Table &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 바이트코드는 V8 가상 머신에서 기계어 코드처럼 동작합니다. 하지만 실제 기계어는 아닙니다.&lt;/p&gt;

&lt;p&gt;함수가 충분히 “뜨거워”지면(자주 호출되면), JIT 컴파일러는 더 빠른 실행을 위해 이를 네이티브 기계어 코드로 최적화합니다.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PrepareFunctionForOptimization&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt; 함수는 다음과 같이 컴파일됩니다:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
devsdk@dave ~/workspace/chromium/v8/v8 % ./out/arm64.release/d8 ~/workspace/chromium/playground/add.js  &lt;span class=&quot;nt&quot;&gt;--allow-natives-syntax&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--turbofan&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--print-opt-code&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; Raw &lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;a, b&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;a + b&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt; Optimized code &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;
optimization_id &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0
source_position &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 12
kind &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; TURBOFAN_JS
name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; add
compiler &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; turbofan
address &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x2be2001001d5

Instructions &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 288&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
0x140000020     0  a9bf7bfd       stp fp, lr, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;sp, &lt;span class=&quot;c&quot;&gt;#-16]!&lt;/span&gt;
0x140000024     4  910003fd       mov fp, sp
0x140000028     8  a9be03ff       stp xzr, x0, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;sp, &lt;span class=&quot;c&quot;&gt;#-32]!&lt;/span&gt;
0x14000002c     c  a9016fe1       stp x1, &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt;, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;sp, &lt;span class=&quot;c&quot;&gt;#16]&lt;/span&gt;
0x140000030    10  f8520342       ldur x2, &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;x26, &lt;span class=&quot;c&quot;&gt;#-224]&lt;/span&gt;



  .-&lt;span class=&quot;s1&quot;&gt;')   .-. .-'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;             _ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;-.    _ &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;-.    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'-.  _ .-'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; _   
 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; OO &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; OO &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;OO  &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;OO  &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; _&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;  OO&lt;span class=&quot;o&quot;&gt;)(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;  OO&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;,--. ,--.  ,-.-&lt;span class=&quot;s1&quot;&gt;')  _.`     \ _.`     \(,------.\     .'&lt;/span&gt;_  
/    _ | |  .&lt;span class=&quot;s1&quot;&gt;'   /  |  |OO)(__...--''(__...--'' |  .---'&lt;/span&gt;,&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'--..._) 
\  :` `. |      /,  |  |  \ |  /  | | |  /  | | |  |    |  |  \  '&lt;/span&gt; 
 &lt;span class=&quot;s1&quot;&gt;'..`''.)|     '&lt;/span&gt; _&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; |  |&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;_/ |  |_.&lt;span class=&quot;s1&quot;&gt;' | |  |_.'&lt;/span&gt; |&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;|  &lt;span class=&quot;s1&quot;&gt;'--. |  |   '&lt;/span&gt; | 
.-._&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;   &lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt; ,|  |_.&lt;span class=&quot;s1&quot;&gt;' |  .___.'&lt;/span&gt; |  .___.&lt;span class=&quot;s1&quot;&gt;' |  .--'&lt;/span&gt; |  |   / : 
&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;      /|  |&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;  &lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;_|  |    |  |      |  |      |  &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;.|  &lt;span class=&quot;s1&quot;&gt;'--'&lt;/span&gt;  / 
 &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-----&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' `--'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--'&lt;/span&gt;  &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'    `--'&lt;/span&gt;      &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'      `------'&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-------&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' 
 
 /* 100줄이 넘는 기계어 코드가 있어 생략되었습니다 */

0x14000013c   11c  97fffffb       bl #-0x14 (addr 0x140000128)

Inlined functions (count = 0)

Deoptimization Input Data (deopt points = 4)
 index  bytecode-offset    pc
     0                2    NA
     1                2    NA
     2                2    NA
     3               -1    9c

Safepoints (stack slots = 6, entries = 2, byte size = 24)
0x1400000bc     9c  slots (sp-&amp;gt;fp): 100000  deopt      3 trampoline:    11c
0x1400000e4     c4  slots (sp-&amp;gt;fp): 000000

RelocInfo (size = 13)
0x1400000b4  full embedded object  (0x0263000446c5 &amp;lt;NativeContext[301]&amp;gt;)
0x1400000b8  near builtin entry
0x1400000e0  near builtin entry
0x140000110  constant pool (size 16)

--- End code ---
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위에 있는 코드는 V8의 현재 최상위 티어 JIT 컴파일러인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Turbofan&lt;/code&gt;과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Turboshaft&lt;/code&gt;를 사용한 예시입니다.&lt;/p&gt;

&lt;h3 id=&quot;maglev와-turbofan&quot;&gt;Maglev와 Turbofan&lt;/h3&gt;
&lt;p&gt;앞서 언급했듯이 V8은 multi-tier JIT 컴파일러를 가지고 있습니다. Maglev는 중간 티어 JIT 컴파일러입니다. Turbofan과 Turboshaft는 높은 수준의 최적화된 코드를 생성하지만 컴파일하는 데 시간이 더 오래 걸립니다.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Compiler&lt;/th&gt;
      &lt;th&gt;Compile Speed&lt;/th&gt;
      &lt;th&gt;Optimization Level&lt;/th&gt;
      &lt;th&gt;Structure&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Maglev&lt;/td&gt;
      &lt;td&gt;빠름&lt;/td&gt;
      &lt;td&gt;낮은 최적화&lt;/td&gt;
      &lt;td&gt;단순&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Turbofan&lt;/td&gt;
      &lt;td&gt;느림&lt;/td&gt;
      &lt;td&gt;높은 최적화&lt;/td&gt;
      &lt;td&gt;복잡&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;V8의 tiering manager는 결정 로직에 따라 주어진 함수에 대해 티어를 적용합니다.&lt;/p&gt;

&lt;h3 id=&quot;turbolev&quot;&gt;Turbolev&lt;/h3&gt;

&lt;p&gt;이름은 &lt;strong&gt;maglev&lt;/strong&gt; + &lt;strong&gt;turboshaft&lt;/strong&gt;에서 유래했습니다. 이 프로젝트는 Maglev의 IR(중간 표현)을 사용하여 기존의 &lt;strong&gt;Turbofan&lt;/strong&gt; 컴파일러 프론트엔드를 대체하는 것을 목표로 하고 있습니다.&lt;/p&gt;

&lt;p&gt;이전의 최상위 티어 JIT 컴파일러는 프론트엔드로 &lt;strong&gt;Turbofan&lt;/strong&gt;을, 백엔드로 &lt;strong&gt;Turboshaft&lt;/strong&gt;를 사용했습니다. Turbofan은 기존의 일반적인 &lt;strong&gt;CFG(Control Flow Graph)&lt;/strong&gt; 기반 접근 방식이 아닌 &lt;strong&gt;Sea of Nodes&lt;/strong&gt;를 최적화에 사용했습니다. 이는 이론적으로는 강력하지만, 복잡성과 유지보수성 측면에서 몇 가지 실용적인 단점이 있었습니다.&lt;/p&gt;

&lt;p&gt;더 자세한 배경과 프로젝트의 시작에 대해 읽어보려면: Darius의 &lt;a href=&quot;https://v8.dev/blog/leaving-the-sea-of-nodes&quot;&gt;Land ahoy: leaving the Sea of Nodes · V8&lt;/a&gt; 를 읽어보세요. :)&lt;/p&gt;

&lt;h2 id=&quot;저는-어떻게-이-프로젝트에-참여하게-되었을까요&quot;&gt;저는 어떻게 이 프로젝트에 참여하게 되었을까요?&lt;/h2&gt;

&lt;p&gt;저는 몇 년 동안 V8 프로젝트의 JS 기능 영역에 기여해왔습니다. 하지만 메모리 관리와 JIT 컴파일러는 여전히 ‘블랙박스’처럼 느껴졌습니다. 외부 기여자로서, 새로운 ECMAScript 기능을 구현할 기회를 찾기가 점점 더 어려워지기도 했고 더 많은 영역에 기여하고 싶어서 블랙박스 내부를 들여다보기 위해 기여 영역을 확장하기로 결정했습니다.&lt;/p&gt;

&lt;p&gt;과거 &lt;a href=&quot;https://blog.seokho.dev/development/2025/02/21/V8-DevLogFloat16Array.html&quot;&gt;Float16Array&lt;/a&gt; CL JIT 부분을 리뷰해 줬던 적이 있는 Darius가 기억 났고, 최근에 v8.dev에 turbolev에 대한 글을 게시한 것을 봤습니다. 저는 제가 도울 일이 있는지 알아보기 위해 이메일을 보냈습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi Darius,&lt;/p&gt;

  &lt;p&gt;I’ve noticed that it’s getting a bit tough to find contribution opportunities related to ECMAScript features as an external contributor. So I was wondering—are there any areas in the compiler side (like Turboshaft or Maglev), or GC/memory stuff, where I could possibly help out?&lt;/p&gt;

  &lt;p&gt;I’d love to learn more and hopefully get involved in a broader range of work in V8.&lt;/p&gt;

  &lt;p&gt;–&lt;/p&gt;

  &lt;p&gt;Regards,&lt;/p&gt;

  &lt;p&gt;Seokho&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Darius 는 친절하게 Turbolev 프로젝트를 제안해줬습니다. 
친절한 가이드에 따라 Turbolev 프로젝트에 참여하기로 마음을 먹었고 가장 온보딩하기 수월한 구현을 찾아보려 했습니다.&lt;/p&gt;

&lt;p&gt;그렇게 첫번째 기여 목표를 찾아 나섰고, 찾은것은  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.atan2&lt;/code&gt; 였는습니다. 이 함수는 비슷한 IEEE754 Binary 연산을 처리하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.pow&lt;/code&gt; 기존 구현 경로가 있었기 때문입니다.&lt;/p&gt;

&lt;p&gt;저는 CL 초안을 만들어 Darius, Marja, Victor, Leszek에게 질문이 담긴 이메일을 보냈고, 답변을 통해  친절한 설명 및 성능 측정 도구인 Pinpoint 관련 도움등을 받을 수 있었습니다.&lt;/p&gt;
&lt;h2 id=&quot;기여-내용&quot;&gt;기여 내용&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.atan2&lt;/code&gt; 최적화를 시작으로 약 4개의 CL에 기여했습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-07-15/list.png&quot; alt=&quot;list.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;제가 최적화한 내용은 다음과 같습니다:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.atan2&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.sqrt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;`Array.prototype.at&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;… 및 리팩토링.&lt;/p&gt;

&lt;p&gt;그중 하나를 소개합니다 -  &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/6708123&quot;&gt;Implement Math.sqrt turbolev&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.sqrt&lt;/code&gt; 함수를 mid, top tier JIT 컴파일러가 지원할 수 있도록 개선했습니다.&lt;/p&gt;

&lt;p&gt;Pinpoint에 따르면 성능이 &lt;strong&gt;61%&lt;/strong&gt; 향상되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-07-15/pinpoint.png&quot; alt=&quot;list.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Victor는 코드리뷰 과정에서 &lt;strong&gt;Amazing&lt;/strong&gt;이라는 표현을 쓸 정도였습니다 ㅎㅎ.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-07-15/victor.png&quot; alt=&quot;victor.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 최적화 과정을 풀어서 설명해보자면:&lt;/p&gt;

&lt;p&gt;Floa64Sqrt maglev IR 노드를 추가했습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/maglev/maglev-ir.h;l=3775-3791;drc=1be580e8347d0656f0f5b4d4dcdcd16ac582be3d&quot;&gt;maglev-ir.h&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Float64Sqrt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FixedInputValueNodeT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FixedInputValueNodeT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

 &lt;span class=&quot;nl&quot;&gt;public:&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;explicit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bitfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constexpr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpProperties&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kProperties&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpProperties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HoleyFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constexpr&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputTypes&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kInputTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValueRepresentation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kHoleyFloat64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SetValueLocationConstraints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GenerateCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MaglevAssembler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessingState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PrintParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ostream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그리고 maglev 그래프 빌더에 MathSqrt를 등록했습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/maglev/maglev-graph-builder.h;l=926;drc=1be580e8347d0656f0f5b4d4dcdcd16ac582be3d&quot;&gt;maglev-graph-builder.h&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MathRound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                 \
  &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MathSqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                  \
  &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MathClz32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                                 \
  &lt;span class=&quot;n&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetPrototypeHas&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;                           \
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 매크로는 리듀서 함수를 선언합니다. C++ 컴파일러가 해당 함수의 구현부가 없는 것을 알려줍니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/maglev/maglev-graph-builder.cc;l=10376-10392;drc=1be580e8347d0656f0f5b4d4dcdcd16ac582be3d&quot;&gt;maglev-graph-builder.cc&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;MaybeReduceResult&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MaglevGraphBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TryReduceMathSqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JSFunctionRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CallArguments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetRootConstant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RootIndex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kNanValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CanSpeculateCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ValueRepresentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value_representation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rep&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ValueRepresentation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kTagged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;ValueNode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;GetFloat64ForToNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;TaggedToFloat64ConversionType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kNumberOrUndefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddNewNode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 리듀서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.sqrt&lt;/code&gt; 같은 고수준 연산을 더 최적화된 저수준 IR 노드인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float64Sqrt&lt;/code&gt;로 변환하는 역할을 합니다. 이 노드는 최상위 티어 JIT인 “turbolev”와 중간 티어 JIT인 “maglev”에서 사용될 것입니다.&lt;/p&gt;

&lt;p&gt;Mid Tier Maglev - arm64:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/maglev/arm64/maglev-ir-arm64.cc;l=838-847;drc=30f71750eac22aa5a941b719a81874c0720a2256&quot;&gt;maglev-ir-arm64.cc&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetValueLocationConstraints&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;UseRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DefineSameAsFirst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GenerateCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MaglevAssembler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;masm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                               &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ProcessingState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DoubleRegister&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ToDoubleRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;DoubleRegister&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result_register&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ToDoubleRegister&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fsqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;JIT 컴파일할 때, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float64Sqrt&lt;/code&gt; 노드는 arm64 아키텍처용 기계어 코드인 &lt;a href=&quot;https://developer.arm.com/documentation/dui0801/h/A64-Floating-point-Instructions/FSQRT--scalar-&quot;&gt;fsqrt&lt;/a&gt;로 컴파일 합니다. 비슷하게 x64에서는 &lt;a href=&quot;https://www.felixcloutier.com/x86/sqrtsd&quot;&gt;SSE 명령어&lt;/a&gt;인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqrtsd&lt;/code&gt;를 컴파일 할 것 입니다.&lt;/p&gt;

&lt;p&gt;For Top-Tier Turbolev 컴파일용:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float64Sqrt&lt;/code&gt; 노드는 turbolev-graph-builder에 의해 소비됩니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/compiler/turboshaft/turbolev-graph-builder.cc;l=4225-4229;drc=1be580e8347d0656f0f5b4d4dcdcd16ac582be3d&quot;&gt;turbolev-graph-builder.cc&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;maglev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessResult&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maglev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maglev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessingState&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SetMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maglev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kContinue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 코드는 Maglev의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float64Sqrt&lt;/code&gt; 노드를 입력으로 사용하여 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float64Sqrt&lt;/code&gt; &lt;strong&gt;Turboshaft 그래프 노드&lt;/strong&gt;를 생성합니다. 여기부터 Turboshaft의 강력한 CFG 기반 백엔드가 Loop Unrolling, Store Elimination, Register Allocation과 같은 추가적인 최적화를 수행하여 더 높은 최적화를 진행합니다.&lt;/p&gt;

&lt;p&gt;따라서, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.sqrt&lt;/code&gt;가 hot and stable 상태가 되면, tiering manager는 Turbolev 컴파일을 트리거 합니다. (이 노드는 동일한 기계어 코드를 생성할 것 입니다. 하지만  Turboshaft가 이제 주변의 모든 코드에 강력한 최적화를 적용해 높은 최적화를 이룰 것 입니다.)&lt;/p&gt;
&lt;h2 id=&quot;concluding&quot;&gt;Concluding&lt;/h2&gt;

&lt;p&gt;위에서 언급한 과정을 통해 저는 V8의 Maglev 및 Turbolev 영역에 훨씬 더 익숙해지고, 블랙 박스를 많이 들여다 봤습니다. 하지만 아직 구현되지 않은 함수도 많고, 기여할 수 있는 기회가 많이 보입니다. 앞으로도 계속 기여하여 더 많은 시야를 얻을 수 있을 것 이라고 기대하고 있습니다. 어느날 이 코드베이스가 완전히 익숙해지면  WASM이나 메모리 등 다른 영역으로 또 한번 나아갈 생각입니다.&lt;/p&gt;

&lt;p&gt;코드 리뷰를 해주고 좋은 가이드를 해준 동료 Darius, Marja, Victor, Leszek에게 감사 인사 드립니다. :).&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><summary type="html">저는 최근들어 V8 기여 범위를 JS 를 구현하는 영역에서 더 낮은 레이어의 컴파일러 파이프라인으로 확장했습니다.</summary></entry><entry><title type="html">V8 커미터가 되었습니다</title><link href="https://blog.seokho.dev/ko/development/2025/05/10/Became-V8-Committer.html" rel="alternate" type="text/html" title="V8 커미터가 되었습니다" /><published>2025-05-10T00:00:00+00:00</published><updated>2025-05-10T00:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2025/05/10/Became-V8-Committer</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2025/05/10/Became-V8-Committer.html">&lt;p&gt;오늘 아침, V8 커미터가 되었습니다.&lt;/p&gt;

&lt;p&gt;지난 2년간 남는 시간 대부분을 V8에 기여하는데 사용했습니다.&lt;/p&gt;

&lt;p&gt;그동안 기여한 주요 내용은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;주요 기능인 Float16Array 구현
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://blog.seokho.dev/ko/development/2024/03/03/V8-Float16Array.html&quot;&gt;V8에 Float16 관련 기능 추가한 첫번째 이야기&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://blog.seokho.dev/ko/development/2025/02/21/V8-DevLogFloat16Array.html&quot;&gt;Float16Array Turbofan Pipeline 개발기 — Weekly Sync with V8 Leader&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;최적화를 통한 일부 연산 성능 향상
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://blog.seokho.dev/ko/development/2024/03/18/V8-optimize-MathHypot.html&quot;&gt;V8의 Math.hypot 최적화 하기 - 반복의 숨은 비용&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;스팩과 다르게 동작하는 잘못된 동작 수정(7년간 방치된 버그 해결)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;누군가한테 “V8 커미터가 되겠다”고 말했던 것 같은데 이제 그 목표를 이룬 것 같아 감개무량합니다.&lt;/p&gt;

&lt;p&gt;저를 포함하여 전 세계에 75명 밖에 없다는 사실이 좀 놀랍기도 하구요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-05-10/members.png&quot; alt=&quot;count&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 프로젝트를 통해 정말 많은 것을 배웠고, 멋진 사람들도 많이 만났습니다.&lt;/p&gt;

&lt;p&gt;작은 기여들이 세상을 조금 더 나아지게, 더 안전하고 더 빠르게 만드는 데 보탬이 되기를 바랍니다.&lt;/p&gt;

&lt;p&gt;앞으로도 커미터로서 계속 최선을 다하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chromium-review.googlesource.com/q/owner:seokho@chromium.org+repo:v8/v8+-status:abandoned&quot;&gt;기여 목록 보기&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-05-10/mail.png&quot; alt=&quot;Render example&quot; /&gt;&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><summary type="html">오늘 아침, V8 커미터가 되었습니다.</summary></entry><entry><title type="html">Float16Array Turbofan Pipeline 개발기 — Weekly Sync with V8 Leader</title><link href="https://blog.seokho.dev/ko/development/2025/02/21/V8-DevLogFloat16Array.html" rel="alternate" type="text/html" title="Float16Array Turbofan Pipeline 개발기 — Weekly Sync with V8 Leader" /><published>2025-02-21T23:00:00+00:00</published><updated>2025-02-21T23:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2025/02/21/V8-DevLogFloat16Array</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2025/02/21/V8-DevLogFloat16Array.html">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;p&gt;이 글에서는 V8의 외부 컨트리뷰터로서 Float16Array를 구현한 이야기를 공유하면서 TurboFan과 Turboshaft의 최종 JIT 최적화에 초점을 맞춥니다. 몇 달에 걸쳐 저는 Google 엔지니어 Shu-Yu Guo와 매주 동기화를 진행하며 플랫폼별 과제를 해결하여 상당한 성능 향상을 달성했습니다.&lt;/p&gt;

&lt;h2 id=&quot;float16array&quot;&gt;Float16Array&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array&quot;&gt;Float16Array&lt;/a&gt;는 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array&quot;&gt;Uint32Array&lt;/a&gt; 혹은  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array&quot;&gt;Float32Array&lt;/a&gt;와 같은 타입 배열입니다. &lt;a href=&quot;https://en.wikipedia.org/wiki/Half-precision_floating-point_format&quot;&gt;16비트 부동 소수점 숫자(float16, 반정밀도)&lt;/a&gt;로 작동합니다. 특정 사용 사례에 적합한 정밀도를 유지하면서 Float32Array 및 Float64Array에 비해 부동 소수점 데이터를 처리하는 메모리 효율적인 방법을 제공합니다.&lt;/p&gt;

&lt;p&gt;Float16Array는 웹 및 JavaScript 기반 애플리케이션에서 성능과 메모리 사용량을 최적화하는 데 사용할 수 있으며, 특히 WebGPU, WebGL 기반 애플리케이션과 같이 빠른 숫자 연산이 필요한 분야에서 유용하게 사용할 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;what-is-v8-and-turbofan-&quot;&gt;What is V8 and TUrBoFan ?&lt;/h2&gt;

&lt;p&gt;본격적으로 시작하기 전에 Turbofan, Turboshaft, 그리고 제가 기여하는 V8에 대해 간략히 소개하겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is V8?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;V8은 JavaScript 코드를 실행하기 위한 자바스크립트 엔진입니다.
V8에는 자바스크립트와 WASM을 실행하고 최적화하기 위한 대규모 파이프라인이 있으며, Chromium(Chrome, Edge, Whale 등의 기반), Node.js, Deno 등을 구성합니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/V8_(JavaScript_engine)&quot;&gt;V8 (JavaScript engine) - Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the TurboFan?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;아시다시피 JS는 인터프리터 위에서 실행되지만, 일반적으로 네이티브 언어(C, C++ 등)보다 느립니다.&lt;/p&gt;

&lt;p&gt;Turbofan은 이러한 성능 격차를 좁히기 위한 최적화 도구입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/turbofan-pipeline.png&quot; alt=&quot;turbofan pipeline&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 포스트에서는 모든 세부사항을 다루지 않을 겁니다. 기회가 된다면 따로 글을 작성하겠습니다.
위 그림을 보면, 입력으로 ByteCodeGraph(V8 자바스크립트 바이트코드에서 빌드된 그래프)가 있고, 출력은 타깃 머신별 코드를 생성해냅니다. 
함수나 연산이 충분히 자주 호출되어 뜨거운 상태(자주 호출되는 상태)가 되면 파이프라인이 실행되어 최적화가 이뤄지고, 결국 머신 코드로 동작하게 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Turboshaft&lt;/em&gt; 는 또 다른 &lt;strong&gt;제어 흐름 그래프 중간 표현(CFG-IR)&lt;/strong&gt;으로, Turbofan과 머신 실행 코드 사이에 위치합니다. Turboshaft의 최종 결과는 실행 가능한 머신 코드가 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JIT란?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JIT(Just-In-Time)는 컴퓨팅에서 성능을 최적화하기 위해 사용되는 기술로, 실행하기 전이 아닌, 실행 시점 직전에 코드를 컴파일합니다. 이~ 방식은 실행되는 환경에 맞춰 코드를 최적화할 수 있으므로, 프로그램이 더 빠르게 동작하도록 돕습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;Just-in-time compilation - Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;histories&quot;&gt;Histories&lt;/h1&gt;

&lt;h2 id=&quot;from-beginning&quot;&gt;From Beginning&lt;/h2&gt;

&lt;p&gt;저는 여가시간에 취미로 기여하는 개인 기여자 입니다.&lt;/p&gt;

&lt;p&gt;2024년 3월 &lt;a href=&quot;https://tc39.es/proposal-float16array/&quot;&gt;스팩에 정의된&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float16Array&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.f16round&lt;/code&gt;, 그리고 관련 DataView를 구현 했습니다.
코드 리뷰는 2023년 12월에 시작되었습니다. 70개의 패치셋과 80개 이상의 파일이 변경되고, 코드 리뷰 전 구현 단계에서 2023년 3~4분기의 개인 시간이 많이 투입될 정도로 거대한 프로젝트였습니다.(&lt;a href=&quot;https://blog.seokho.dev/development/2024/03/03/V8-Float16Array.html&quot;&gt;관련 포스트&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;리뷰어들과 저는 변경이 너무 방대하니, 기능 구현과 Turbofan JIT 지원 부분을 분리하기로 합의했습니다. 결국 &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/5082566/comment/0b15c828_7cd95f6d/&quot;&gt;여기에서&lt;/a&gt; 항상 deoptimization하도록 하는 코드를 추가했는데, 이 코드는 이후 Darius에 의해 &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/5378406&quot;&gt;개선되었습니다&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;2024년 3월 말, 저는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float16Array&lt;/code&gt;가 릴리즈 준비가 되었다고 판단했고, Shu에게 “Intent to Ship 프로세스를 진행할 준비가 되었느냐”는 메일을 보냈습니다.
그에 대한 답변은, 제가 위에서 언급한 Deoptimization 코드를 해결해야 한다는 것이었습니다. 적어도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fp16.h&lt;/code&gt; 안에 있는 소프트웨어 에뮬레이션 함수를 호출해야 한다고 했습니다. 즉, Turbofan 파이프라인 이후에 런타임 함수를 호출하는 형태가 필요했습니다.&lt;/p&gt;

&lt;p&gt;지금은 그 말이 어떤 의미인지 알지만, 당시에는 “Turbofan이 뭔지, 어떻게 동작하는지”를 알아내야 하는 상황이었습니다. 그래서 일요일 대부분의 시간을 투자해가며 Turbofan 코드를 읽고 작성하기 시작했고, ‘float16 값을 변환’하는 빌트인 함수를 호출하는 파이프라인 단계를 구현했습니다.&lt;/p&gt;

&lt;p&gt;그러나… 2분기, 3분기에 개인 사정(시험 준비)으로 우선순위를 바꿔야 했습니다.&lt;/p&gt;

&lt;p&gt;시간은 정말 빠르게 지나가 4분기가 되었습니다. 종종 Float16Array 관련 메일이나 작업이 오긴 했지만, 더딘 진행과 기회를 놓칠 수 있다는 불안감이 있었습니다.&lt;/p&gt;

&lt;p&gt;4분기 초, Shu로부터 메일이 왔습니다. Float16Array는 이제 개발이 가능하고, x64와 ARM에서 float16 &amp;lt;-&amp;gt; float64 변환 작업을 Ilya가 진행 중이라는 내용이었습니다.&lt;/p&gt;

&lt;p&gt;그래서 “내장 함수를 호출하자”라는 저의 기존 계획을 바꿔 다음과 같은 새로운 계획을 세웠습니다:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;머신에서 float16 변환을 지원하는 패치가 준비될 때까지 대기&lt;/li&gt;
  &lt;li&gt;변환 코드를 검토해 범위를 파악&lt;/li&gt;
  &lt;li&gt;js-native-context-specialization의 “Always Unoptimize” 코드를 제거&lt;/li&gt;
  &lt;li&gt;각 단계마다 Turbofan 노드를 연결해 Float16Array를 지원&lt;/li&gt;
  &lt;li&gt;Ilya가 구현한 노드나 파이프라인과 연결 (어느 단계가 최적인지 조사 필요)&lt;/li&gt;
  &lt;li&gt;float16을 지원하지 않는 머신을 위한 Fallback으로 (uint16을 사용하는) 런타임 함수를 호출하는 방안도 고려&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;시간은 흘러 11월이 되었고,  코드를 읽고 시간이 있을 때 위의 계획을 구현하려고 노력했습니다. 11월의 어느 날, 업스트림의 일부 변경 사항이 실험용 Float16Array 코드와 부분적으로 충돌하는 것을 발견했습니다. 위에서 언급한 것 처럼 충돌이 일어날 수 있다는 우려가 현실이 된 것 입니다. 그리고 이것이 중복 작업을 만들 수 있다고 생각했습니다. 어떻게 해야할 지 혼란스러웠고,  길을 잃은 것 같았습니다.&lt;/p&gt;

&lt;p&gt;그래서, 구현 상태나 진행 상황, 그리고 막힌 부분을 더 자주 공유해야겠다고 결심했습니다. 11월 중순, 작은 멘토링이나 매니징 도움을 기대하며 “주간 싱크”를 요청하는 메일을 보냈습니다:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi syg,&lt;/p&gt;

  &lt;p&gt;And I think the turbofan and turboshaft code is much more complex than I thought… Is there any mentoring system or programme for this?&lt;/p&gt;

  &lt;p&gt;I may need to tighten the feedback loop for myself to release in this year. If you don’t mind, can I send some kind of weekly or some periodic update email that might include what I’m considering or what I’m stuck on?&lt;/p&gt;

  &lt;p&gt;Regard&lt;/p&gt;

  &lt;p&gt;Seokho&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi syg,&lt;/p&gt;

  &lt;p&gt;Turbofan, Turboshaft 코드가 생각보다 훨씬 복잡한 것 같아요… 
이에 대한 멘토링 시스템이나 프로그램이 있나요?&lt;br /&gt;
올해 안에 배포하려면 피드백 루프를 더 강화해야 할 것 같습니다. 
괜찮다면 매주 또는 주기적으로 제가 고려하고 있는 사항이나 막혀 있는 사항을 포함한 업데이트 이메일을 보내도 될까요?&lt;/p&gt;

  &lt;p&gt;Regard&lt;/p&gt;

  &lt;p&gt;Seokho&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이 메일을 보낼 때, 제 코드 이해 부족이나 역량을 드러내고 시간을 뺏는 게 아닐까 걱정도 됐고, 기회를 잃게 되지 않을까 두려움도 있었습니다.&lt;/p&gt;

&lt;p&gt;정말 기쁘게도 다행히 그가 좋다고 답해줬습니다.&lt;/p&gt;

&lt;h1 id=&quot;progression&quot;&gt;Progression:&lt;/h1&gt;

&lt;p&gt;이렇게 해서 주간 싱크를 본격적으로 시작하게 되었습니다.&lt;/p&gt;

&lt;h2 id=&quot;first-week---sync-the-context&quot;&gt;First week - Sync the Context&lt;/h2&gt;
&lt;p&gt;첫 주에는, 위의 히스토리와 맥락을 정리해 Shu에게 보여주기 위한 준비를 했습니다. 그리고 임시 &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/6026409&quot;&gt;WIP CL&lt;/a&gt;을 열어 현재 진행 상황을 공유했습니다. 이메일 내용도 위와 같은 히스토리로 가득 습니다. 길을 찾기를 바라면서 메일을 보냈습니다.&lt;/p&gt;

&lt;p&gt;이메일 내용 일부를 발췌하면 다음과 같습니다:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;B. The plan:&lt;/p&gt;

  &lt;p&gt;Sooo, It seems machine support is now possible thanks to Ilya’s changes. I noticed the following in the Turboshaft graph builder:&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNARY_CASE(TruncateFloat64ToFloat16RawBits, TruncateFloat64ToFloat16RawBits)&lt;/code&gt;.&lt;/p&gt;

  &lt;p&gt;One remaining task appears to be removing the force-deoptimize code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/compiler/js-native-context-specialization.cc&lt;/code&gt; and adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNARY_CASE&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ChangeFloat16ToFloat64&lt;/code&gt;.&lt;/p&gt;

  &lt;p&gt;Additionally, should we consider retaining software calculations for cases where machines do not support FP16 operations? If so, where would be the best place to handle this in Turbofan?&lt;/p&gt;

  &lt;p&gt;So… the question is whether my assumption about the remaining task is correct.&lt;/p&gt;

  &lt;p&gt;C. Next action plan:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;당시 다음 단계에 무엇을 해야할지 불확실한 느낌이 들어 B. 계획 부분에 대해 동기화하기를 기대했습니다.&lt;/p&gt;

&lt;p&gt;그리고 Shu는 정말 고맙게도 디테일한 계획을 제시해주었습니다. :)&lt;/p&gt;

&lt;p&gt;계획 요약:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;마이크로벤치마크 작성&lt;/li&gt;
  &lt;li&gt;float64-&amp;gt;float16 저장(즉 Float16Array에 쓰기) 시의 Deoptimization 제거&lt;/li&gt;
  &lt;li&gt;필요하다면, 새로운 ‘truncation operator’ 추가&lt;/li&gt;
  &lt;li&gt;해당 새 오퍼레이터를 TruncateFloat64ToFloat16RawBits 오퍼레이터로 낮춤(lower) (즉 소프트웨어 에뮬레이션이 아닌 경로를 동작시키기)&lt;/li&gt;
  &lt;li&gt;지원 안 되는 환경에선 C 함수를 호출하여 truncation 처리(소프트웨어 에뮬레이션 경로)&lt;/li&gt;
  &lt;li&gt;float16-&amp;gt;float64 (즉 Float16Array에서 값 읽기)도 같은 방식으로 반복&lt;/li&gt;
  &lt;li&gt;마이크로벤치마크 성능이 향상되었는지 확인&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;second-week---execute-what-we-synced&quot;&gt;Second Week - Execute what we synced&lt;/h2&gt;

&lt;p&gt;둘째 주에는, 첫 주에 싱크 용으로 만들어뒀던 WIP CL을 버리고, 간단한 마이크로벤치마크 코드를 작성했습니다:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100000000&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Float16Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// heater&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// heater&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;N = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ITERATION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timeEnd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;SUM = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;BYTE LENGTH: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BYTES_PER_ELEMENT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(이 코드는 “항상 Deoptimization” 상태에서의 결과) 실행 시간:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;N =  100000000
console.timeEnd: store, 2242.493000
console.timeEnd: load, 1853.342000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이번주에는 주로 소스 코드의 ‘store’ 경로를 확인하면서, float16 변환을 처리하기 위해 Turbofan 노드를 어떻게 생성할지를 살폈습니다. &lt;a href=&quot;https://v8.github.io/tools/head/turbolizer/index.html&quot;&gt;turbolizer&lt;/a&gt; 를 사용해 그래프도 확인하고, representation change phase를 디버깅했습니다.&lt;/p&gt;

&lt;p&gt;하지만 제가 생성한 그래프 빌드/수정 방법이 맞는 건지 확신이 서지 않았습니다. (쓰지 말아야 할 코드를 억지로 넣은 느낌이었거든요)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/turbofan-node.png&quot; alt=&quot;turbofan nodes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위에서 말한 어색하다고 느낀 지점을 포함해 메일로 공유했습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;…&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;I found a code chunk of calling external reference functions but I need to figure out how to connect with our TruncateFloat64ToFloat16RawBits.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;PLAN:
5.1: Investigate where I should call / process platform specific code to process TruncateFloat64ToFloat16RawBits node from your suggestion ‘machine_lowering’ code.  (Maybe if there are some existing codes there will be great)&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;5.2: Write the code to call the software/hardware support code.&lt;/p&gt;

  &lt;p&gt;5.3: Find out how to separate Float32 in representation-change steps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;외부 참조 함수를 호출하는 코드 덩어리를 찾았지만 TruncateFloat64ToFloat16RawBits와 연결하는 방법을 알아내야 합니다.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;PLAN:
5.1: 제안하신 ‘machine_lowering’ 코드에서 플랫폼별 코드를 어디에서 호출/처리하여 TruncateFloat64ToFloat16RawBits 노드를 처리해야 하는지 조사합니다.  (기존 코드를 알 수 있다면 좋을 것 같습니다.)&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;5.2: 소프트웨어/하드웨어 지원 코드를 호출하는 코드를 작성합니다.&lt;/p&gt;

  &lt;p&gt;5.3: Float32를 representation-change 단계에서 분리하는 방법을 알아봅니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;third-week---software-emulation-work&quot;&gt;Third Week - Software Emulation Work!&lt;/h2&gt;

&lt;p&gt;세 번째 싱크는 2024년 12월 1일이었습니다. 마침 일요일이었고, 한국에서 첫눈이 내리던 날이었네요. (이걸 Shu에게 메일로 얘기했더라고요!)&lt;/p&gt;

&lt;p&gt;모호한 이름 충돌도 일으키고 있는 불필요한   &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kJSFloat16TruncateWithBitcast&lt;/code&gt;관련 코드를 제거했습니다.&lt;br /&gt;
드디어 lower reducer에서 외부 레퍼런스 함수 호출 코드를 작성했습니다.&lt;/p&gt;

&lt;p&gt;그런데 arm64에서 illegal hardware instruction 문제가 생겼습니다:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;devsdk@Dave ~/workspace/chromium/v8/v8 % ./out/arm64.debug/d8 &lt;span class=&quot;nt&quot;&gt;--js-float16array&lt;/span&gt; ~/workspace/chromium/playground/float16array_float16.js  
zsh: illegal hardware instruction  ./out/arm64.debug/d8 &lt;span class=&quot;nt&quot;&gt;--js-float16array&lt;/span&gt;  

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;M1 arm64와 관련된 무언가라고 생각했습니다. (나중에 보니 무한 재귀 호출 문제가 원인이었어요)&lt;/p&gt;

&lt;p&gt;외부 레퍼런스 함수(즉, C 함수를 직접 호출)로만 구현했을 때 하드웨어 연산이 아님에도 불구하고, 이미 200% 이상 속도가 빨라졌습니다!&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;devsdk@Dave ~/workspace/chromium/v8/v8 % ./out/x64.release/d8 &lt;span class=&quot;nt&quot;&gt;--js-float16array&lt;/span&gt; ~/workspace/chromium/playground/float16array_float16.js  
N &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  100000000  
console.timeEnd: store, 770.435000  
SUM &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  0  
BYTE LENGTH:  2  

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그리고, 다음 주 계획을 공유했죠:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;그래프 빌딩 개선&lt;/li&gt;
  &lt;li&gt;load 경로 구현&lt;/li&gt;
  &lt;li&gt;몇 가지 이슈 조사…&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;forth-week---weird-week&quot;&gt;Forth Week - Weird week&lt;/h2&gt;

&lt;p&gt;네 번째 주. 약간 이상하고 힘든 한 주였습니다. 모두가 기억하듯 &lt;a href=&quot;(https://news.koreaherald.com/view.php?ud=20241204050016)&quot;&gt;대통령이 지난 수요일에 계엄령을 선포했다가 국회에서 중지&lt;/a&gt;시켰거든요…&lt;/p&gt;

&lt;p&gt;그리고 Shu도 이메일에서 “뉴스에서 봤어요! 격동의 시기인 것 같은데, 이번 CL은 걱정하지 않아도 될 것 같습니다”라고 답을 보냈습니다. 🤣&lt;/p&gt;

&lt;p&gt;개인적으로도 이번 주에는 시간이 넉넉하지 않아 작업량이 적었습니다.&lt;/p&gt;

&lt;p&gt;그래도 load 경로를 구현하고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DoNumberToFloat16RawBits&lt;/code&gt;라는 함수를 구현했습니다.&lt;/p&gt;

&lt;p&gt;다음 주 계획:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;마이크로벤치마크 실행&lt;/li&gt;
  &lt;li&gt;제가 제거했던 kJSFloat16TruncateWithBitcast가 정말 필요 없는지 확인&lt;/li&gt;
  &lt;li&gt;“load”에 대한 머신 지원 코드 구현&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;fifth-week---hardware-instruction-works-but-another-issue-come&quot;&gt;Fifth Week - Hardware instruction works but another issue come&lt;/h2&gt;

&lt;p&gt;다섯 번째 싱크도 시간이 짧았습니다. 일본 여행 계획이 있었거든요. 여행 전까지, 하드웨어 지원 경로를 구현하고, 왜 ‘illegal instruction’ 이슈가 생겼는지 파악했습니다.&lt;/p&gt;

&lt;p&gt;Email content:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi syg&lt;/p&gt;

  &lt;p&gt;I’m going on an away trip this weekend, so I’m trying to sync now.&lt;/p&gt;

  &lt;p&gt;And with hardware support (only for store yet):&lt;/p&gt;

  &lt;p&gt;devsdk@Dave ~/workspace/chromium/v8/v8 % ./out/arm64.release/d8 –js-float16array ~/workspace/chromium/playground/float16array_float16.js&lt;/p&gt;

  &lt;p&gt;N =  100000000&lt;/p&gt;

  &lt;p&gt;console.timeEnd: store, 133.083000&lt;/p&gt;

  &lt;p&gt;(It super fast)&lt;/p&gt;

  &lt;p&gt;I kept kJSFloat16TruncateWithBitcast to use instruction selection to fix illigal instruction issue that we mentioned in previous email on arm64.It was caused by by infinite call loop TrucateFloat64ToFloat16RawBits -&amp;gt; ReduceXXX -&amp;gt; TrucateFloat64…&lt;/p&gt;

  &lt;p&gt;The arm64 native support that kept kJSFloat16TruncateWithBitcast through ReduceIfReachableChange makes the x64 software path that implemented our reducers is broken. I’ll have a look at it after my trip.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;안녕하세요. Syg!&lt;/p&gt;

  &lt;p&gt;이번 주말에 여행을 떠날 예정이라 지금 메일을 보냅니다.&lt;/p&gt;

  &lt;p&gt;그리고 하드웨어 지원(아직 스토어에만 해당)도 제공됩니다:&lt;/p&gt;

  &lt;p&gt;devsdk@Dave ~/workspace/chromium/v8/v8 % ./out/arm64.release/d8 –js-float16array ~/workspace/chromium/playground/float16array_float16.js&lt;/p&gt;

  &lt;p&gt;N =  100000000&lt;/p&gt;

  &lt;p&gt;console.timeEnd: store, 133.083000&lt;/p&gt;

  &lt;p&gt;(매우 빠릅니다)&lt;/p&gt;

  &lt;p&gt;이전 이메일에서 언급 한 illigal instruction 문제를 해결하기 위해 명령어 선택을 사용하기 위해 kJSFloat16TruncateWithBitcast를 유지했습니다.이 문제는 무한 호출 루프 TrucateFloat64ToFloat16RawBits -&amp;gt; ReduceXXX -&amp;gt; TrucateFloat64…로 인해 발생했습니다.&lt;/p&gt;

  &lt;p&gt;reduceIfReachableChange를 통해 kJSfloat16TruncateWithBitcast를 유지했던 arm64 네이티브 지원 덕분에 구현했던 Reducer의 x64 소프트웨어 경로가 깨졌습니다. 여행 후에 한번 살펴보겠습니다&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;그리고 일본 여행 관련 얘기도 좀 했어요. (이 사진을 찍었습니다!)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/japan.png&quot; alt=&quot;Japan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;결국 software emulation load 경로도 구현했습니다.&lt;/p&gt;

&lt;p&gt;이후, 전체 테스트를 돌려봤습니다.&lt;/p&gt;

&lt;p&gt;그리고 마침내! 코드 정리를 조금 거친 뒤 리뷰를 받기 위한 CL을 준비했습니다.&lt;/p&gt;

&lt;p&gt;최종 벤치마크 결과:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Without any optimization (original)
N =  100000000
console.timeEnd: store, 2242.493000
console.timeEnd: load, 1853.342000

Software calculation (calling the fp16.h):
N =  100000000
console.timeEnd: store, 379.250000
console.timeEnd: load, 606.833000

arm64 hardware operation:
N =  100000000
console.timeEnd: store, 128.042000
console.timeEnd: load, 603.542000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;store의 경우 약 500% 이상, load는 약 300% 향상되었습니다!&lt;/p&gt;

&lt;h2 id=&quot;sixth-week---the-review-phase&quot;&gt;Sixth Week - THE REVIEW PHASE&lt;/h2&gt;

&lt;p&gt;이제… 리뷰 단계입니다!&lt;/p&gt;

&lt;p&gt;변경된 코드 중 핵심을 요약하면:&lt;/p&gt;

&lt;p&gt;하드웨어 지원을 통해 머신 코드를 생성하기 위해 터보샤프트에서 파이프라인 단계로 정의된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float16-lowering-reducer.h&lt;/code&gt;를 만들었습니다. (추후 &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/6227844&quot;&gt;추가 작업으로 삭제&lt;/a&gt;되었습니다!) 그리고 float64를 float16으로 변경하기 위한 외부 참조 함수의 대상을 변경했습니다. 마지막으로 &lt;a href=&quot;https://github.com/tc39/test262/blob/main/harness/byteConversionValues.js#L55-L69&quot;&gt;tc39/test262에 정의된 테스트코드&lt;/a&gt;에 다양한 edge case를 추가했습니다.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;edgeCases&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// an integer which rounds down under ties-to-even when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2049&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2048&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// an integer which rounds up under ties-to-even when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2051&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2052&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// smallest normal float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006103515625&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006103515625&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// largest subnormal float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006097555160522461&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006097555160522461&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// smallest float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.960464477539063&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.960464477539063&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// largest double which rounds to 0 when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.9802322387695312&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// smallest double which does not round to 0 when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.980232238769532&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.960464477539063&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// a double which rounds up to a subnormal under ties-to-even when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;8.940696716308594&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1920928955078125&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// a double which rounds down to a subnormal under ties-to-even when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4901161193847656&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1920928955078125&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// the next double above the one on the previous line one&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.490116119384766&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.7881393432617188&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// max finite float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65504&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65504&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// largest double which does not round to infinity when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;65519.99999999999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65504&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// lowest negative double which does not round to infinity when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;65519.99999999999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65504&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// smallest double which rounds to a non-subnormal when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.000061005353927612305&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006103515625&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// largest double which rounds to a subnormal when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0000610053539276123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00006097555160522461&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;NaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;NaN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// smallest double which rounds to infinity when cast to float16&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65520&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;65520&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;merged&quot;&gt;Merged!&lt;/h2&gt;

&lt;p&gt;마침내 이 CL은 1월 27일에 머지되었습니다. 거의 반년 걸렸네요. 그래도 이제 Turbofan/Turboshaft 파이프라인에 꽤 익숙해졌습니다!&lt;/p&gt;

&lt;p&gt;2024년 말쯤 끝나리라 예상했는데, 결국 1월 말이 되었습니다.&lt;/p&gt;

&lt;p&gt;자바스크립트 API 프론트엔드에서부터 JIT 머신 코드 생성 백엔드까지, 정말 길고도 긴 여정이었습니다.&lt;/p&gt;

&lt;p&gt;CL: &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/6043415&quot;&gt;chromium-review.googlesource.com/c/v8/v8/+/6043415&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;그리고 머지 후, 배포 준비를 하는 동안엔 미국 여행을 다녔습니다. Shu도 만났고요! 제가 미국 산호세에 체류 중일 때 이 CL이 머지되었어요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/guest.jpeg&quot; alt=&quot;Google Guest&quot; /&gt;&lt;/p&gt;

&lt;p&gt;V8 관련 기여, 그리고 제 커리어에 대한 이야기도 나눴습니다!&lt;/p&gt;

&lt;p&gt;아마 이 내용은 따로 여행 관련 포스트로 따로 다룰 수도 있을 것 같네요.&lt;/p&gt;

&lt;p&gt;어쨌든, 이제 이 기능을 릴리즈하기 위해 몇 가지 단계를 더 진행해야 합니다.&lt;/p&gt;

&lt;h2 id=&quot;prepare-to-ship&quot;&gt;Prepare to ship&lt;/h2&gt;

&lt;p&gt;Blink-dev 구글 그룹에서 +3 LGTMs를 받아야 기능을 공개할 수 있습니다. (흔히 말하는 Intended to Ship, I2S)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://groups.google.com/u/2/a/chromium.org/g/blink-dev/c/0zw4GWcf-Ig&quot;&gt;Intent to Ship: Float16Array&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;드디어 2025년 2월 14일, +3LGTMs를 받았습니다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/3lgtms.png&quot; alt=&quot;3 LGTMs&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;and-ship&quot;&gt;And… Ship!&lt;/h2&gt;

&lt;p&gt;퍼저에서 발견된 버그를 일부 수정하고  쪽에 테스트 케이스를 추가했습니다. 일부 자동화에서 감지된 문제를 확인하기 위해 일주일을 기다렸습니다.&lt;/p&gt;

&lt;p&gt;Shu가 Blink 쪽에서 퍼저가 감지하는 버그를 일부 수정했습니다. 일부 자동화에서 감지된 문제를 확인하기 위해 일주일을 기다린 끝에 마침내 기능 플래그를 기본으로 활성화하도록 전환했습니다! 제가 개발에 참여한 다른 기능이 세상에 공개되었습니다.&lt;/p&gt;

&lt;p&gt;Chrome M135(2025년 3월 중순 출시)부터 새로운 Float16Array를 사용할 수 있습니다!&lt;/p&gt;

&lt;p&gt;Feature Entry: &lt;a href=&quot;https://chromestatus.com/feature/5164400693215232&quot;&gt;https://chromestatus.com/feature/5164400693215232&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2025-02-22/feature-status.png&quot; alt=&quot;Chrome 135&quot; /&gt;&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="TC39" /><category term="ECMAScript" /><category term="Javascript" /><category term="Optimization" /><category term="Float16Array" /><summary type="html">Introduction</summary></entry><entry><title type="html">V8의 Math.hypot 최적화 하기 - 반복의 숨은 비용</title><link href="https://blog.seokho.dev/ko/development/2024/03/18/V8-optimize-MathHypot.html" rel="alternate" type="text/html" title="V8의 Math.hypot 최적화 하기 - 반복의 숨은 비용" /><published>2024-03-18T21:00:00+00:00</published><updated>2024-03-18T21:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2024/03/18/V8-optimize-MathHypot</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2024/03/18/V8-optimize-MathHypot.html">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Chrome, NodeJS 등 자바스크립트를 실행하는 런타임의  엔진인 V8에 구현되어 있는 javascript 함수 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.hypot&lt;/code&gt; 의 속도를 약 200% 향상했습니다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.hypot&lt;/code&gt; 함수는 거리를 계산하는 데 많이 사용되는 함수입니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hypotenuse = 빗변
  &lt;img width=&quot;200&quot; alt=&quot;image&quot; src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/d7a1ae04-c109-4734-a579-ca48d3f9cbdc&quot; /&gt;
  &lt;img width=&quot;150&quot; alt=&quot;image&quot; src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/17e4cfd6-31b8-4d43-b9dc-d944961ed907&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이 글에서는 성능 저하를 해결하기 위해 생각했던 가설과 속도 저하가 발생했던 원인 및 해결책을 소개할 것입니다.&lt;/p&gt;

&lt;p&gt;CL: https://chromium-review.googlesource.com/c/v8/v8/+/5329686&lt;/p&gt;

&lt;h2 id=&quot;과정&quot;&gt;과정&lt;/h2&gt;

&lt;h3 id=&quot;이슈-발견&quot;&gt;이슈 발견&lt;/h3&gt;

&lt;p&gt;V8의 이슈를 목록을 보던 중 삼각형의 빗변 길이를 계산할 때 사용하는 Math.hypot 함수가 곱셈 연산자 등을 활용하여 구현 한 것 보다 수십 배 느리다는 이슈를 발견했습니다.&lt;/p&gt;

&lt;p&gt;처음에 이 이슈를 발견했을 왜 다른 빌트인 함수(Math.pow, **)를 사용한 것 보다 Math.hypot을 쓴 게 특별히 더 느릴까? 라는 생각을 했습니다.&lt;/p&gt;

&lt;p&gt;아래는 이슈에 같이 첨부된 퍼포먼스 측정을 위한 코드입니다.&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000_000&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
	&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hypot&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hypot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
	&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;91.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;performance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
	&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; took &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;performance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;실제로 이 코드를 실행하면 보면 곱셈(*)을 사용한 것과 상당한 차이가 난다는 것을 알 수 있습니다.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Runtime&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;*&lt;/td&gt;
      &lt;td&gt;103.292ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hypot&lt;/td&gt;
      &lt;td&gt;1584.417ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;**&lt;/td&gt;
      &lt;td&gt;664.958ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pow&lt;/td&gt;
      &lt;td&gt;666.458ms&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;mathhypot-구현체-살펴보기&quot;&gt;Math.hypot 구현체 살펴보기&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.hypot&lt;/code&gt;함수는 &lt;a href=&quot;https://v8.dev/docs/torque&quot;&gt;torque&lt;/a&gt;라는 언어로 작성되어 있고, &lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/builtins/math.tq;l=398-441;drc=8fcd3f809ba5c71f7a29bc6623c1f93a9eac72fe&quot;&gt;src/builtins/math.tq&lt;/a&gt; 에 위치해 있습니다.&lt;/p&gt;

&lt;p&gt;Torque는 타입스크립트와 비슷한 문법을 가진 V8내에서 사용하는 &lt;a href=&quot;http://언어입니다.is&quot;&gt;언어입니다.&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ES6 #sec-math.hypot&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;transitioning&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;javascript&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;builtin&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MathHypot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;js&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;implicit&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NativeContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;receiver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSAny&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absValues&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AllocateZeroedFixedDoubleArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oneArgIsNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ToNumber_Inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]));&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Float64IsNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;oneArgIsNaN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Float64Abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;absValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;float64_or_hole&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;absValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;absValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;V8_INFINITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;V8_INFINITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oneArgIsNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;kNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;dcheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Kahan summation to avoid rounding errors.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Normalize the numbers to the largest one to avoid overflow.&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compensation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;absValues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ValueUnsafeAssumeNotHole&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;summand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compensation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;preliminary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;summand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;compensation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preliminary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;summand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;preliminary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;가설-1-allocate가-느린가&quot;&gt;가설 1: Allocate가 느린가?&lt;/h3&gt;

&lt;p&gt;먼저, 메모리를 할당/해제 반복적으로 한다면 메모리 관리 비용으로 인해 느려질 것으로 추정했습니다.&lt;/p&gt;

&lt;p&gt;이 가설을 테스트하기 위해 메모리를 할당하는 구문(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AllocateZeroedFixedDoubleArray&lt;/code&gt;) 을 제거하고 arguments를 직접 사용하게 변경했습니다.&lt;/p&gt;

&lt;p&gt;그러나, 퍼포먼스가 드라마틱하게 증가하진 않았습니다.&lt;/p&gt;

&lt;h3 id=&quot;가설-2-tonumber_inline-의-비용이-높은가&quot;&gt;가설 2: ToNumber_Inline 의 비용이 높은가?&lt;/h3&gt;

&lt;p&gt;ToNumber &lt;a href=&quot;https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tonumber&quot;&gt;표준을 보면&lt;/a&gt; 다양한 경우를 분기 처리하고 있어 비용이 클 수 있다는 가설을 세웠습니다.&lt;/p&gt;

&lt;p&gt;이 가설이 맞는지 테스트 하기 위해 파라미터의 값이 Number 타입인지 체크하고, Float64로  UnsafeCast하여 테스트를 진행했습니다.&lt;/p&gt;

&lt;p&gt;성능 향상이 0.5~2% 대로 미미했기 때문에  이 가설은 문제의 핵심 원인이 아니라고 판단했습니다.&lt;/p&gt;

&lt;h3 id=&quot;가설-3-부차적인-연산의-비용이-높은가&quot;&gt;가설 3: 부차적인 연산의 비용이 높은가?&lt;/h3&gt;

&lt;p&gt;위 구현을 보면 빗변을 계산하는 구문 이외에 절댓값으로 변환하는 것과 &lt;a href=&quot;https://en.wikipedia.org/wiki/Kahan_summation_algorithm&quot;&gt;Kahan summation&lt;/a&gt; 알고리즘을 수행하는 등 별도의 연산이 포함되어 있습니다.
저는 이 부차적인 연산이 성능에 영향을 줄 것 이라는 가설을 세웠습니다.&lt;/p&gt;

&lt;p&gt;이러한 알고리즘 구현을 제거하고, 테스트하기 위해 위 함수 상단에 파라미터가 2개인 경우 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqrt( a ^ 2 + b ^ 2)&lt;/code&gt; 만 계산하도록 구현하고 테스트 해봤습니다.&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ToNumber_Inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]));&lt;/span&gt;
	  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ToNumber_Inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;V8_INFINITY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;V8_INFINITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;V8_INFINITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Float64Max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Float64IsNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;kNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;Float64Sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;테스트 결과 놀라울 만큼 빨라졌습니다.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Runtime&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;*&lt;/td&gt;
      &lt;td&gt;104.041ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hypot&lt;/td&gt;
      &lt;td&gt;814.667ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;**&lt;/td&gt;
      &lt;td&gt;670.709ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pow&lt;/td&gt;
      &lt;td&gt;674.583ms&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;위 구현은 간단하게 구현하기 위해 arguments 길이가 2인 경우에만 실행되도록 구현했습니다.&lt;/p&gt;

&lt;p&gt;위 테스트에 이어서 위 길이가 2인 경우만 계산하는 로직을 제거하고, 아래에 있는 구현에 부차적인 연산을 제거하는 테스트를 수행했습니다.&lt;/p&gt;

&lt;p&gt;그러나 이번 테스트에서는 다시 속도가 느려졌습니다.&lt;/p&gt;

&lt;p&gt;따라서,  부차적인 로직을 제거한 것이 빨라진 것의 원인이라고 보기는 어려울 것 입니다.&lt;/p&gt;

&lt;h2 id=&quot;현상-분석-왜-빨라진-것-인가&quot;&gt;현상 분석: 왜 빨라진 것 인가&lt;/h2&gt;

&lt;p&gt;이제 성능이 향상되는 현상을 발견했습니다.&lt;/p&gt;

&lt;p&gt;이 현상의 원인을 설명할 수 있다면 이 최적화에 대한 CL(PR과 같은 개념입니다)을 제출할 수 있을 것입니다.&lt;/p&gt;

&lt;p&gt;우선 코드에서 크게 사라진 부분이라고 한다면, 반복문일 것입니다.&lt;/p&gt;

&lt;p&gt;반복문이 원인일 가능성이 높아진 상황에서 실험을 해보기로 합니다. 아래의 코드를 Math.hypot 구현체에 추가 했습니다.&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드의 삽입으로 200ms 의 지연이 발생 했습니다.&lt;/p&gt;

&lt;p&gt;이 현상에 대해 두 가지의 가설을 세워 검증했습니다.&lt;/p&gt;

&lt;h3 id=&quot;가설-4--torque로-작성되어-csa로-컴파일된-loop는-비효율적인가&quot;&gt;가설 4:  torque로 작성되어 CSA로 컴파일된 loop는 비효율적인가?&lt;/h3&gt;

&lt;p&gt;이 가설은 “CSA(&lt;a href=&quot;https://v8.dev/blog/csa&quot;&gt;Code Stub Assembler&lt;/a&gt;)로 컴파일 되는 torque는 CSA로 직접 구현한 것 보다 for loop 동작이 느리게 수행된다”는 가설입니다.&lt;/p&gt;

&lt;p&gt;마치 어셈블리로 직접 구현 하면 일부 구간에선 빠르게 동작할 수 있는 것처럼, 이 가설을 검증하기 위해 CSA로 직접 구현해 비교해 보기로 합니다.&lt;/p&gt;

&lt;p&gt;CSA로 구현하여 비교한 결과 평균적으로 아주 약간 빠른걸 알 수 있었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;512&quot; alt=&quot;image&quot; src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/1528ff51-3c0c-4fb1-a6a9-dcae57999cda&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그러나 이 차이는 미미하기 때문에 성능 저하의 핵심 원인은 아닐 것입니다.&lt;/p&gt;

&lt;h3 id=&quot;가설-5-및-결론--loop의-숨겨진-cost가-있는가&quot;&gt;가설 5 및 결론 : Loop의 숨겨진 cost가 있는가?&lt;/h3&gt;

&lt;p&gt;반복문의 유무로 큰 차이가 발생하는 이유에 대해 면밀히 고민해 보다가 낸 결론입니다.&lt;/p&gt;

&lt;p&gt;반복문에는 숨겨진 비용이 존재합니다.&lt;/p&gt;

&lt;p&gt;반복문의 진입 시 비교하고, 반복 탈출을 위하여 n 번 즉 n+1, 증가 연산도 마찬가지로 반복문 내에서 n번 실행되게 됩니다.&lt;/p&gt;

&lt;p&gt;다시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.hypot&lt;/code&gt; 구현체로 돌아가 살펴보면, 총 두 개의 반복문이 있는 것을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;그렇다면 파라미터가2개일 때 6번의 비교 연산과 4번의 증가 연산이 반복문을 위해 소비되고 있음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;여기서 실행 횟수 N이 커지게 될 경우 N * 6 만큼 연산량이 소비될 수 있으며 이에 따라 실행시간이 차이 난 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;개선&quot;&gt;개선&lt;/h2&gt;

&lt;p&gt;따라서, 파라미터의 길이가 3보다 작은 경우 반복문 없이 실행되도록 하여 최적화를 했습니다.&lt;/p&gt;

&lt;p&gt;이 과정에서 파라미터가 3개인 경우에는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Kahan_summation_algorithm&quot;&gt;Kahan summation&lt;/a&gt; 알고리즘을 방정식으로 정리하여 적용했습니다.&lt;/p&gt;

&lt;div class=&quot;language-ts highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FastMathHypot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;otherwise&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Slow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;label&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Slow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FastMathHypot&lt;/code&gt;의 전체 구현체는 &lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/builtins/math.tq;l=398;drc=2cfc118b6d316f90b4e6c167deeab43d39588522&quot;&gt;여기서&lt;/a&gt; 살펴보실 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;결론&quot;&gt;결론&lt;/h2&gt;

&lt;p&gt;아래는 최적화 이후 실행 시간입니다.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Runtime&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;*&lt;/td&gt;
      &lt;td&gt;104.041ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;hypot&lt;/td&gt;
      &lt;td&gt;814.667ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;**&lt;/td&gt;
      &lt;td&gt;670.709ms&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pow&lt;/td&gt;
      &lt;td&gt;674.583ms&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;위 결과에서 볼 수 있듯 최적화 이전 실행시간(1584.417ms) 대비 약 194% 향상되었음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;여러 번 실행해 본 결과 180~200%의 성능 향상 폭을 얻었음을 알 수 있었습니다.&lt;/p&gt;

&lt;p&gt;이번 최적화에서는 메모리의 할당부터, ToNumber, 부차적인 연산, For loop와 관련된 가설을 세웠습니다. 이 가설들을 검증해 가며 for loop 관련 가설이 옳은 가설임을 알게 되었습니다. 여기서 loop의 숨겨진 비용을 찾아냈고 그 비용을 제거하여 V8을 개선했습니다.&lt;/p&gt;

&lt;p&gt;여기서 배울 수 있었던 점은 반복문에는 반복문 자체를 위한 비용이 있고, 이 비용은 상황에 따라 큰 오버헤드로 작용할 수 있다는 점이겠습니다.&lt;/p&gt;

&lt;p&gt;마지막으로,&lt;/p&gt;

&lt;p&gt;이 글을 퇴고 해주신 &lt;a href=&quot;https://www.atobaum.dev/&quot;&gt;김현영 님께&lt;/a&gt; 감사인사 드립니다.&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="TC39" /><category term="ECMAScript" /><category term="Javascript" /><category term="Optimization" /><summary type="html">Introduction</summary></entry><entry><title type="html">V8에 Float16 관련 기능 추가한 첫번째 이야기</title><link href="https://blog.seokho.dev/ko/development/2024/03/03/V8-Float16Array.html" rel="alternate" type="text/html" title="V8에 Float16 관련 기능 추가한 첫번째 이야기" /><published>2024-03-03T09:00:00+00:00</published><updated>2024-03-03T09:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2024/03/03/V8-Float16Array</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2024/03/03/V8-Float16Array.html">&lt;p&gt;오늘 V8에 Float16과 관련된 기능을 머지했습니다. (&lt;a href=&quot;https://en.wikipedia.org/wiki/Half-precision_floating-point_format&quot;&gt;Float16은 IEEE754에서 정의하는 반정밀도 부동소숫점입니다.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;CL: https://chromium-review.googlesource.com/c/v8/v8/+/5082566&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/8dec4d39-d284-4805-bebb-3216a6816ceb&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Javascript 엔진에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float16Array&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataView.getFloat16&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataView.setFloat16&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Math.fround16&lt;/code&gt; 을 추가했습니다.&lt;/p&gt;

&lt;p&gt;변화한 파일은 총 82개, -409 +1385 에 달하는 꽤 사이즈가 큰 변화였습니다.&lt;/p&gt;

&lt;p&gt;이슈를 잡고 머지하기까지 거의 6개월에 걸친 시간이 걸렸네요.&lt;/p&gt;

&lt;p&gt;2023년 7월, 주로 Blink에 기여하며 CSS/HTML에 한정되어 있는 기여 대상을 V8을 통해 Javascript에 기여하겠다는 방향을 새롭게 정했습니다.&lt;/p&gt;

&lt;p&gt;이미 Blink에 다수 기여하며 커미터 권한을 가지고 있어 Chromium 워크플로우에 익숙하기 때문에 적절한 난이도의 이슈를 잡고 해결해 나가면서 지식을 확장하면 되겠단 판단을 했습니다.&lt;/p&gt;

&lt;p&gt;그렇게 &lt;a href=&quot;https://bugs.chromium.org/p/v8/issues/detail?id=14012&amp;amp;q=owner%3Ame&amp;amp;can=2&quot;&gt;Implement Float16Array&lt;/a&gt; 라는 이슈를 발견했고, ArrayBuffer와 전반적인 메모리 관리를 배울 수 있겠다는 생각과, 가뭄에 단비처럼 나타난 구현 테스크란 점을 고려해서 이슈를 붙잡았습니다.&lt;/p&gt;

&lt;p&gt;구현을 준비하고 구현하고, 코드 리뷰하는 과정에 다양한 우여곡절이 많았습니다.&lt;/p&gt;

&lt;p&gt;전부 담지는 못하겠지만 짤막하게 과정을 적어봤습니다.&lt;/p&gt;

&lt;h2 id=&quot;구현-과정&quot;&gt;구현 과정&lt;/h2&gt;

&lt;h3 id=&quot;stage-3-표준-살펴보기&quot;&gt;Stage-3 표준 살펴보기&lt;/h3&gt;

&lt;p&gt;https://tc39.es/proposal-float16array/&lt;/p&gt;

&lt;p&gt;우선 표준을 살펴봤습니다.&lt;/p&gt;

&lt;p&gt;Float16Array는 &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 3 proposal로써 구현되기를 기대하는 기능&lt;/a&gt;으로 표준을 보며 구현하면 될 것이라는 생각을 했습니다.&lt;/p&gt;

&lt;p&gt;표준 내용을 보면 알겠지만, 각 타입별로 저장하거나 불러올 때 변환 시 float16 타입이 추가된 점과 DataView, Math에 관련 기능이 추가된다는 점을 알 수 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;구현-지점-찾기&quot;&gt;구현 지점 찾기&lt;/h3&gt;

&lt;p&gt;코드를 보며 구현 지점을 찾았습니다. V8은 DRY 원칙을 최대한 지키려고 하여 매크로를 적극적으로 사용하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/e13d2ede-d1ae-4546-b995-e81647aef41f&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이런 식으로 말이죠.&lt;/p&gt;

&lt;p&gt;가끔 chromium source에서 심볼을 못 따라가고 메크로로 prefix나 suffix가 붙는 것 때문에 처음 보면 검색하기 어렵다는 경험을 했습니다. 다만 시간이 흘러 학습되고 나서 구현할 때는 상당히 편하기도 했습니다.&lt;/p&gt;

&lt;p&gt;저기에 타입을 추가하면서 컴파일 에러가 발생하는 지점을 찾아 미구현 사항을 보완하며 수정지점을 찾으면 되겠다는 전략을 세웠습니다.&lt;/p&gt;

&lt;h3 id=&quot;float16-에-대하여&quot;&gt;Float16 에 대하여&lt;/h3&gt;

&lt;p&gt;위 이미지에서 볼 수 있듯이 C type을 지정해야 합니다. 우선 모든 빌드 Target에 대해 float16을 지원하는지 미지수였고, 이 부분은 컴파일러 옵션과 로우레벨 최적화 관련된 변화가 필요할 것으로 판단했습니다.&lt;/p&gt;

&lt;p&gt;관련 변화를 한 번에 하려고 RISC-V 스펙과 x86 스펙을 보면서 구현을 시도하려 했었는데, 생각보다 변화가 필요한 영역이 너무 넓어지는 경향이 있어 관련한 변화는 분리가 가능한 문제로 보고 분리하여 구현하는 게 좋겠다는 의견과 함께 Google의 V8 커미터인 syg@ (감사합니다!) 에게 질문 메일을 남겼고 답변으로 방향을 어느 정도 잡게 되었습니다.&lt;/p&gt;

&lt;p&gt;따라서 컴파일러 및 언어(혹은 하드웨어)가 지원하는 Native float 16 타입을 사용하지 않고, 2바이트의 같은 크기를 가진 uint16_t 타입을 활용하여 float16을 구현해야겠단 생각을 했습니다.&lt;/p&gt;

&lt;h3 id=&quot;변환-로직-구현하기&quot;&gt;변환 로직 구현하기&lt;/h3&gt;

&lt;p&gt;처음에는 변환 알고리즘을 찾고 이해하는데 시간을 많이 썼습니다. 이미 구현되어 있는 구현체는 꽤 있었고 비트연산과 float 곱셈의 원리를 이용하여 &lt;a href=&quot;https://gist.github.com/rygorous/2156668&quot;&gt;구현된 로직을&lt;/a&gt; 사용하기로 했습니다. (이는 추후 코드 리뷰로 이미 Chromium 내에서 사용하던 &lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:third_party/fp16/src/include/fp16/fp16.h&quot;&gt;모듈로&lt;/a&gt; 변경됩니다.)&lt;/p&gt;

&lt;p&gt;C++로 구현된 구현체뿐만 아닌 &lt;a href=&quot;https://v8.dev/docs/csa-builtins&quot;&gt;CSA (Code Stub Assembler)&lt;/a&gt;로도 해당 구현체를 구현해야 합니다.&lt;/p&gt;

&lt;p&gt;어셈블리어로 구현하는 느낌과 유사했습니다. 조금 더 편한 어셈블리어 느낌을 받았습니다.&lt;/p&gt;

&lt;p&gt;따라서 아래처럼 C++ 구현체를 CSA 코드로 구현하는 작업도 진행했습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/86d565f2-5ceb-4255-9460-c62b6a79256e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;변환-로직-적용&quot;&gt;변환 로직 적용&lt;/h3&gt;

&lt;p&gt;이제 메모리에 넣고 뺄 때 위 변환 로직을 적용해야 합니다.&lt;/p&gt;

&lt;p&gt;v8에서는 그 부분을 Template Specialization으로 적극 구현되어 있습니다.&lt;/p&gt;

&lt;p&gt;따라서 값을 메모리에 넣고 뺄 때 부동 소수점 타입(double, float)을 변환하여 저장할 수 있도록 구현했습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/189ff8c0-6f85-43f3-8a2b-932ba3ae7967&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위 이미지는 elements.cc에서 double 타입을 float16 으로 표현된 uint16_t 값을 반환하는 Template Specialized 함수입니다.&lt;/p&gt;

&lt;p&gt;또한 표준에서 정의하는 DataView.getFloat16, DataView.setFloat16, Math.fround16 함수에 해당 변환 로직을 적용합니다.&lt;/p&gt;

&lt;p&gt;아래는 DataView의 getFloat16 구현체입니다. &lt;a href=&quot;https://v8.dev/docs/torque&quot;&gt;torque&lt;/a&gt; 라는 언어로 구현되어 있고 컴파일하면 CSA코드로 컴파일됩니다. 따라서 CSA로 구현된 구현체를 연결할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/b385da7a-e4c8-41f4-b57f-cc73981cc238&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;jit-막기-deoptimize&quot;&gt;JIT 막기: Deoptimize&lt;/h3&gt;

&lt;p&gt;V8의 &lt;a href=&quot;https://v8.dev/docs/turbofan&quot;&gt;Turbofan&lt;/a&gt;과 &lt;a href=&quot;https://v8.dev/blog/maglev&quot;&gt;Maglev&lt;/a&gt; 파이프라인을 타게 되면 머신코드로 컴파일되는 JIT이 동작하게 됩니다. 아직 float16 타입은 머신에서 지원하지 않고, 추후 개선을 위해 소프트웨어적으로 구현해야 하므로 바이트코드 그래프를 만들 때 의도적으로 float16 타입이면&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Deoptimize&lt;/code&gt; 노드를 추가하여 최적화 동작을 막도록 했습니다.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
  &lt;img margin=&quot;auto&quot; width=&quot;402&quot; alt=&quot;image&quot; src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/a8eb1c86-0b57-48b9-a212-83edfe657a54&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;JIT 지원을 임시로 막기 위해 별도의 조건 없이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Deoptimize&lt;/code&gt; 노드를 추가하면 deopt loop을 형성하는 문제가 있는데 해결을 위해 작업을 진행할 예정입니다.&lt;/p&gt;

&lt;h3 id=&quot;테스트코드&quot;&gt;테스트코드&lt;/h3&gt;

&lt;p&gt;이미 Test262, mjsunit 테스트를 통해 TypedArray에 대한 테스트가 충분히 진행되고 있었습니다. 저는 여기에 Float16Array를 적용하여 실패하는 지점을 보완하고 Float16타입의 특성을 가진 테스트 케이스를 추가하였습니다.&lt;/p&gt;

&lt;h3 id=&quot;코드-리뷰&quot;&gt;코드 리뷰&lt;/h3&gt;

&lt;p&gt;코드 리뷰 과정이 거의 3개월 걸린 것 같습니다. 변화량도 많고 비동기로 커뮤니케이션을 진행하다 보니 많은 시간이 소요되었습니다. 리뷰를 통해 많은 부분 개선되고 더 깔끔하게 구현체가 정리된 것 같습니다.&lt;/p&gt;

&lt;p&gt;이 글을 빌어 제 CL을 리뷰해 준 syg@, cbruni@, dmercadier@, dmercadier@ 에 감사 인사드립니다!&lt;/p&gt;

&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;각 단계마다 길을 잃기도 하고 잘못된 길을 들어가서 한참 헤매는 과정을 겪었습니다. 덕분에 시간은 많이 들었지만 v8의 내부 구조와 경로를 많이 파악할 수 있었습니다. 사이즈도 크고 리뷰도 오래 걸려 처음 v8에 기여를 시작한 CL이지만 다른 기여들이 먼저 머지되었었네요.&lt;/p&gt;

&lt;p&gt;직접 d8을 컴파일 하게 되면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--js_float16array&lt;/code&gt; 라는 옵션을 발견할 수 있습니다! 그 옵션과 함께 Float16Array을 사용해 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;실제 유저에게 이 기능이 노출되는 건 아마도 시간이 소요될 것 같습니다. 여전히 Turbofan optimization Loop, Hardware support 등 해결해야 할 문제가 있기 때문입니다. 이 지점도 꾸준히 기여하여 언젠간 Float16Array가 세상에 등장할 수 있도록 노력하겠습니다.&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="TC39" /><category term="Float16" /><category term="IEEE754" /><category term="ECMAScript" /><category term="Javascript" /><summary type="html">오늘 V8에 Float16과 관련된 기능을 머지했습니다. (Float16은 IEEE754에서 정의하는 반정밀도 부동소숫점입니다.)</summary></entry><entry><title type="html">JS 클로저는 표준에서 어떻게 다루고 있을까?</title><link href="https://blog.seokho.dev/ko/development/2024/01/30/js-closure.html" rel="alternate" type="text/html" title="JS 클로저는 표준에서 어떻게 다루고 있을까?" /><published>2024-01-30T03:00:00+00:00</published><updated>2024-01-30T03:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2024/01/30/js-closure</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2024/01/30/js-closure.html">&lt;p&gt;클로저란 무엇일까?&lt;/p&gt;

&lt;p&gt;간략하게 알고 있는 것은 outer function에서 선언한 요소를 inner function에서 접근 가능한 동작을 말한다는 것이었다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;왜 클로저라고 불릴까? &lt;a href=&quot;https://en.wikipedia.org/wiki/Closure_%28computer_programming%29#History_and_etymology&quot;&gt;위키피디아에 따르면&lt;/a&gt; Peter Landian이 1964 년에 그의 SECD 머신에서 사용되는 개념으로 클로저라는 용어를 처음 정의했다고 한다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이 동작은 정확히 어떻게 보장받고 있는 걸까?&lt;/p&gt;

&lt;p&gt;ECMA Script를 살펴보자. ES15(2024)를 기준으로 한다.&lt;/p&gt;

&lt;p&gt;JS에서는 모든 함수는 Function object로 객체화된다.&lt;/p&gt;

&lt;p&gt;여기서 사용되는 표준을 하나씩 살펴보자&lt;/p&gt;

&lt;p&gt;함수가 객체화될 때 &lt;strong&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-functiondeclarationinstantiation&quot;&gt;10.2.11 FunctionDeclarationInstantiation&lt;/a&gt;&lt;/strong&gt; 라는 추상 연산에 의해 객체화가 된다.&lt;/p&gt;

&lt;p&gt;여기서 추상 연산은 표준에서 사용되는 함수라고 생각하면 편하다.&lt;/p&gt;

&lt;p&gt;그리고 [[형식으로]] 표기된 공간은 internal slot이라고 불리는데 js에서는 노출 안되는 프로퍼티라고 생각하면 편하다.&lt;/p&gt;

&lt;h3 id=&quot;함수는-객체다&quot;&gt;함수는 객체다&lt;/h3&gt;

&lt;p&gt;실제로 함수가 선언되면서 객체화가 되는지 살펴보자.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody&quot;&gt;표준을 살펴보면,&lt;/a&gt; 함수의 syntax 분석이 완료되면 syntax tree는 각각 타입에 맞게 떨어진다, 각각 FunctionBody, ConciseBody, GeneratorBody, AsyncFunctionBody, AsyncConciseBody로 등으로 부른다.&lt;/p&gt;

&lt;p&gt;이 중에서 한 가지 케이스를 살펴보자.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FunctionBody : FunctionStatementList
1. Return ? **EvaluateFunctionBody** of FunctionBody with arguments functionObject and argumentsList.
ConciseBody : ExpressionBody
...이하생략

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody&quot;&gt;15.2.3 Runtime Semantics: EvaluateFunctionBody&lt;/a&gt; 표준을 따라가 보면, 해당 표준에서 드디어 위에서 언급한 연산이 호출되는걸 볼 수 있다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FunctionBody : FunctionStatementList
1. Perform ? **FunctionDeclarationInstantiation**(functionObject, argumentsList).
2. Return ? Evaluation of FunctionStatementList.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;자 그럼 실제 함수 선언이 이 연산을 통해 객체화가 된다는 사실을 알았다.&lt;/p&gt;

&lt;h3 id=&quot;값-참조&quot;&gt;값 참조&lt;/h3&gt;

&lt;p&gt;클로저에 대해 더 알아보기 전에, 함수 내에서 값을 참조할 때 어떤 일이 일어나는지 살펴보자&lt;/p&gt;

&lt;p&gt;값을 참조한다는 것은 함수 내의 assign 로직을 살펴보면 좋을 것이다,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation&quot;&gt;13.15.2 Runtime Semantics: Evaluation&lt;/a&gt;&lt;/strong&gt; 표준을 살펴보면 assign 로직이 어떻게 평가되는지 알 수 있다. 평가되는 로직을 살펴보면 GetValue라는 연산을 호출하는 것을 알 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/7fb97bcb-9bee-4b10-b946-5e3addfd2380&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-getvalue&quot;&gt;6.2.5.5 GetValue&lt;/a&gt;&lt;/strong&gt; 이 표준을 살펴보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/d2d06625-9a02-452a-8c05-b35ee483e829&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;4.c를 잘 보면 GetBindingValue라는 연산을 수행하게 된다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-object-environment-records-getbindingvalue-n-s&quot;&gt;9.1.1.2.6 GetBindingValue ( N, S )&lt;/a&gt;&lt;/strong&gt; GetBindingValue의 표준을 살펴보면 다음처럼 [[BindingObject]] Internal Slot 값에서 가져온다는 사실을 알 수 있다!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/e0314236-85e6-433f-a6db-d16b841d7f22&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;함수-객체화-표준-lexical-scope에-접근한다&quot;&gt;함수 객체화 표준: lexical scope에 접근한다&lt;/h3&gt;

&lt;p&gt;다시  함수가 객체화되는 곳을 살펴보자&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/1477d678-99a7-4945-870e-057d180ac03f&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;LexicallyScopedDeclareations of code를 돌면서 lexEnv에 값을 설정하는 것을 볼 수 있다.&lt;/p&gt;

&lt;p&gt;그렇게 36.c 에 가면 &lt;strong&gt;&lt;a href=&quot;https://tc39.es/ecma262/#sec-object-environment-records-setmutablebinding-n-v-s&quot;&gt;9.1.1.2.5 SetMutableBinding ( N, V, S )&lt;/a&gt;&lt;/strong&gt; 을 호출하게 되는데,&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/103bd4d9-a191-4220-a472-2c295a39bc51&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;위에서 서술했던 GetValue에서 사용하는 같은 internal 슬롯에 값을 쓰는 것을 볼 수 있다.&lt;/p&gt;

&lt;p&gt;정리하자면 함수가 선언되며 객체가 되는데, 이 객체가 생성되는 과정에서 생성 당시의 Lexical Scope에 존재하는 선언을 함수 오브젝트의 internal slot [[BindingObject]] 에 집어넣고, 함수 호출이 일어난다면 assign 등, 식별자의 값을 사용해야 할 때 해당 [[BindingObject]]에 있는 값을 가져와서 활용하는 것이다.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c1&quot;&gt;// outer function object 생성, [[BindingObject]]은 global 스코프 내 정의된 값&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// iner function object 생성, [[BindingObject]]에 들어있는 global 스코프에 정의된 값 + test&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;c1&quot;&gt;// GetValue를 사용하여 [[BindingObject]]의 test값을 가져와 반환 후 값 증가&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//  0 출력. 왜냐하면 &quot;[[BindingObject]]&quot; 에는 outer 정보까지 다 들어있는 &quot;객체&quot;가 반환되기 때문&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 1 출력. 왜냐하면 내부의 슬롯의 값이 업데이트되었기 때문&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;우리는 이 일련의 동작 과정과 표준에서 보장하는 클로저 라는 기능을 사용하고 있다.&lt;/p&gt;

&lt;p&gt;실제로 v8 구현체가 표준을 따르는지 간략히 살펴보았는데, 표준과 완전히 1대1 대응되진 않고, 전반적인 흐름이 표준을 만족하는 것으로 보인다.&lt;/p&gt;

&lt;p&gt;아래는 큰 흐름에서 두 가지 지점이다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/parsing/parser.cc;l=871;drc=25a9dc176029598d968de92e6cfd7dcb5e6246e4;bpv=1;bpt=1&quot;&gt;함수를 파싱하는 부분&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:v8/src/runtime/runtime-scopes.cc;l=798;bpv=0;bpt=1&quot;&gt;런타임에서 값을 찾는 부분&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;값을 사용하는 지점이 많다 보니 값을 찾는 부분을 명확히 전부 파악하기에 시간이 많이 소요될 것 같다.&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="TC39" /><category term="ECMAScript" /><category term="Javascript" /><summary type="html">클로저란 무엇일까?</summary></entry><entry><title type="html">JS array sort((a,b) =&amp;gt; a &amp;lt; b) 가 정렬을 보장하지 않는 이유</title><link href="https://blog.seokho.dev/ko/development/2024/01/28/issue-14595-function-array-array-sort.html" rel="alternate" type="text/html" title="JS array sort((a,b) =&gt; a &lt; b) 가 정렬을 보장하지 않는 이유" /><published>2024-01-28T15:00:00+00:00</published><updated>2024-01-28T15:00:00+00:00</updated><id>https://blog.seokho.dev/ko/development/2024/01/28/issue-14595-function-array-array-sort</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2024/01/28/issue-14595-function-array-array-sort.html">&lt;p&gt;얼마 전에 crbug에서 기여할 항목을 찾다가 신기한 이슈를 발견했다.&lt;/p&gt;

&lt;p&gt;https://bugs.chromium.org/p/v8/issues/detail?id=14595&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/ac5b1d07-5dc2-4178-8d4c-f86768e5788b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;제보된 이슈의 내용을 요약하면 Array.prototype.sort의 동작과 TypedArray.prototype.sort 과 동작이 다르고, 다른 js 엔진과 compare function 동작이 다르다는 것이다. 이게 어떻게 된 일일까?&lt;/p&gt;

&lt;p&gt;다음의 코드를 보았을 때 어떤 실행 결과를 기대하는가?&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;얼핏 보기에는 정렬이 되기를 기대할 것이다.&lt;/p&gt;

&lt;p&gt;하지만 결과는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v8&lt;/code&gt; 을 기준으로 정렬되지 않는다.&lt;/p&gt;

&lt;p&gt;JSC, SpiderMonkey는 정렬을 해준다.&lt;/p&gt;

&lt;p&gt;이 차이는 왜 발생할까?&lt;/p&gt;

&lt;p&gt;ES15(2024) 표준을 살펴보면&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/cf911834-9232-4e8a-8789-c8f351b45f00&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;5. Let sortedList be ? &lt;strong&gt;SortIndexedProperties(obj, len, SortCompare, SKIP-HOLES)&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;실질적으로 정렬을 수행하는 내용은 SortIndexedProperties 에서 수행하는 것으로 보인다.&lt;/p&gt;

&lt;p&gt;해당 내용을 살펴보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/978dd1d6-998c-4fc9-a802-ad81427c948f&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;표준에서 abstract operation은 표준에서 쓰는 함수로 읽으면 편하다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;4. Sort items using &lt;strong&gt;an implementation-defined sequence&lt;/strong&gt; of calls to SortCompare. If any such call returns an abrupt completion, stop before performing any further calls to SortCompare and return that Completion Record&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;여기서 주목할 단어는 implementation-defined다. 이 말은 구현 측에서 정의하도록 열어둔다는 뜻이다.&lt;/p&gt;

&lt;p&gt;표준 내용을 조금 더 읽어보면 해당 implementation-defined 만족해야 할 내용이 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;There must be some mathematical permutation π of the non-negative integers less than itemCount, such that for every non-negative integer j less than itemCount, the element old[j] is exactly the same as new[π(j)].&lt;/li&gt;
    &lt;li&gt;Then for all non-negative integers j and k, each less than itemCount, if ℝ(SortCompare(old[j], old[k])) &amp;lt; 0, then π(j) &amp;lt; π(k).&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;만족해야 할 내용을 요약하면 다음과 같다.&lt;/p&gt;

&lt;p&gt;배열의 길이보다 작은 모든 정수 j, k가 있다고 할 때,&lt;/p&gt;

&lt;p&gt;a = arr[j], b = arr[k], compareFunction(a, b) 호출이  반환한 숫자가 0보다 작은 경우 a, b 순이여야 한다.&lt;/p&gt;

&lt;p&gt;다시 원래의 문제로 돌아가 보자&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;compare 함수가 반환하는 값은 어떤 값일까?&lt;/p&gt;

&lt;p&gt;false 혹은 true다. 이는 ToNumber 스팩에 의해서 최종적으로 0과 1을 소비하게 된다.&lt;/p&gt;

&lt;p&gt;정렬을 수행하는 implementation-defined 이 요구하는 요구사항을 만족하는 값이 아니다. 따라서 이는 구현 측에서 결정이 되며 정렬을 수행하지 않는 것 또한 표준을 만족한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/DevSDK/devsdk.github.io/assets/18409763/eb7cc80d-9912-4c49-821e-15ad28230b1e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;따라서 이 이슈는 버그로 분류되진 않는다. 구글의 JS 리더 syg@의 더블체크를 받으면서 이슈를 닫았다.&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="TC39" /><category term="ECMAScript" /><category term="Javascript" /><category term="crbug" /><summary type="html">얼마 전에 crbug에서 기여할 항목을 찾다가 신기한 이슈를 발견했다.</summary></entry><entry><title type="html">Jest는 Code Coverage를 어떻게 측정할까? (V8)</title><link href="https://blog.seokho.dev/ko/development/2023/09/23/how-to-collect-coverage-jest-v8.html" rel="alternate" type="text/html" title="Jest는 Code Coverage를 어떻게 측정할까? (V8)" /><published>2023-09-23T00:00:01+00:00</published><updated>2023-09-23T00:00:01+00:00</updated><id>https://blog.seokho.dev/ko/development/2023/09/23/how-to-collect-coverage-jest-v8</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2023/09/23/how-to-collect-coverage-jest-v8.html">&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;회사에 커버리지를 중심으로 한 워크플로우를 만들고자 하는데 커버리지가 정확히 무엇인지 알고자 했다.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;이 글을 통해서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jest --CollectCoverage --coverageProvider=v8&lt;/code&gt;는 어떻게 커버리지를 측정하는지 jest 를 시작으로 가볍게 v8을 살펴보며 커버리지를 어떻게 측정하는지 알게 될 것이다.&lt;/p&gt;

&lt;p&gt;컴파일러 이론을 미리 알고 보면 더 읽기 수월할 것이다.&lt;/p&gt;

&lt;h2 id=&quot;coverage&quot;&gt;Coverage?&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Software_engineering&quot;&gt;소프트웨어 공학&lt;/a&gt;에서 &lt;strong&gt;코드 커버리지&lt;/strong&gt;는 특정 Test Suite가 실행될 때 프로그램의 &lt;strong&gt;소스 코드&lt;/strong&gt;가 실행되는 정도를 백분율로 측정한 것이다 - 위키피디아&lt;/p&gt;

&lt;/blockquote&gt;

&lt;p&gt;우리는 jest를 통해서 코드를 테스트하고 있으며 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;—CollectCoverage&lt;/code&gt; 옵션을 통해 테스트 커버리지를 측정할 수 있다.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;testFunc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;~/hooks/func&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;testFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2023-09-23/coverage.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;coverage-in-jest&quot;&gt;Coverage in jest&lt;/h2&gt;

&lt;p&gt;이 커버리지는 어떻게 측정하고 있는 걸까? 그리고 무엇일까?&lt;/p&gt;

&lt;p&gt;V8을 기준으로 설명해 보고자 한다.&lt;/p&gt;

&lt;p&gt;Jest는 내부적으로 &lt;a href=&quot;https://github.com/SimenB/collect-v8-coverage&quot;&gt;collect-v8-coverage&lt;/a&gt; 패키지를 쓴다&lt;/p&gt;

&lt;p&gt;내부 구현체를 보면&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;startInstrumenting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Profiler.enable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Profiler.startPreciseCoverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Start&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;callCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;detailed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start로 표현된 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Profiler.startPreciseCoverage&lt;/code&gt; Chrome Devtools Protocol을 사용하여 커버리지 측정을 진행한다.&lt;/p&gt;

&lt;p&gt;이는 V8의 커버리지 측정 기능을 활용하기 위해 V8에 요청을 보내는 명령어로 아래의 링크에서 구체적인 내용을 확인 할 수 있다.&lt;/p&gt;

&lt;p&gt;https://chromedevtools.github.io/devtools-protocol/tot/Profiler/&lt;/p&gt;

&lt;p&gt;커버리지는 저 옵션을 통해 가져오게 되는 걸 알게 되었다.&lt;/p&gt;

&lt;p&gt;구체적으로 저 프로토콜을 활용해 어떻게 커버리지를 측정하고 있을까?&lt;/p&gt;

&lt;p&gt;아래는 해당 프로토콜을 이용해 아래 “test 함수의” 커버리지를 계산하는 예제다.&lt;/p&gt;
&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Session&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;inspector&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promisify&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promisify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Profiler.enable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Profiler.startPreciseCoverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;callCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;detailed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Profiler.takePreciseCoverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Profiler.stopPreciseCoverage&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;postP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Profiler.disable&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;file://&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 코드를  nodejs환경에서 실행하면 다음의 결과를 콘솔에 출력할 것이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;scriptId&quot;: &quot;481&quot;,
    &quot;url&quot;: &quot;file:///Users/seokho/workspace/chromium/playground/v8_test.js&quot;,
    &quot;functions&quot;: [
        {
            &quot;functionName&quot;: &quot;main&quot;,
            &quot;ranges&quot;: [
                {
                    &quot;startOffset&quot;: 182,
                    &quot;endOffset&quot;: 777,
                    &quot;count&quot;: 1
                }
            ],
            &quot;isBlockCoverage&quot;: false
        },
        {
            &quot;functionName&quot;: &quot;test&quot;,
            &quot;ranges&quot;: [
                {
                    &quot;startOffset&quot;: 372, // byte offset
                    &quot;endOffset&quot;: 454,
                    &quot;count&quot;: 1
                },
                {
                    &quot;startOffset&quot;: 409,
                    &quot;endOffset&quot;: 431,
                    &quot;count&quot;: 0
                }
            ],
            &quot;isBlockCoverage&quot;: true
        },
        {
            &quot;functionName&quot;: &quot;&quot;,
            &quot;ranges&quot;: [
                {
                    &quot;startOffset&quot;: 699,
                    &quot;endOffset&quot;: 729,
                    &quot;count&quot;: 0
                }
            ],
            &quot;isBlockCoverage&quot;: false
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여기서 볼 수 있듯이 몇 번 호출되었는지 블록 커버리지인지 여부를 포함한 정보를 소스레벨에서 조회할 수 있게 된다. offset은 바이트 단위로 소스코드 내에서의 위치 정보를 알 수 있다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;compiler-overview&quot;&gt;Compiler overview&lt;/h2&gt;

&lt;p&gt;아래 내용은 컴파일러의 동작에 대한 대략적인 이해가 있다면 더 이해하기 수월할 것이다.&lt;/p&gt;

&lt;p&gt;아래 이미지를 통해 간략히 설명하고 넘어갈 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2023-09-23/v8.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;컴파일러는 다양한 파이프라인을 가지고 있는데 소스코드를 받아 중간의 AST를 구성하게 된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/uploads/2023-09-23/ast.png&quot; alt=&quot;Untitled&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 AST를 이용하여 (v8 turboshaft)IR; Intermediate Representation을 만드는데 여기까지를 컴파일러의 프론트엔드라고 부른다.&lt;/p&gt;

&lt;p&gt;만들어진 IR을 입력으로 받아 목적코드를 만들거나 바이트코드를 생성하는 단계를 컴파일러의 백엔드라고 불린다. 이를 통해 소스코드가 VM과 네이티브 머신에서 실행될 수 있는 형태로 변화하는 것이다.&lt;/p&gt;

&lt;p&gt;정리하자면, 코드를 트리로 만들고 트리를 중간 표현식으로 만들고, 중간 표현식을 통해 목적코드를 생성하는 과정을 거쳐 컴파일러는 코드를 컴파일한다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-to-check-coverage-in-v8&quot;&gt;How to check coverage in V8&lt;/h2&gt;

&lt;p&gt;그렇다면 이를 실행시켜주는 V8은 이 실행 여부를 어떻게 계산하고 있을까?&lt;/p&gt;

&lt;p&gt;V8은 두 가지 방식으로 커버리지를 측정할 수 있게 지원한다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Best effort
    &lt;ol&gt;
      &lt;li&gt;실제 실행 성능에 큰 영향을 주지 않지만 GC등에 의해 데이터를 잃을 수도 있다.
        &lt;ol&gt;
          &lt;li&gt;&lt;a href=&quot;https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-getBestEffortCoverage&quot;&gt;Profiler.getBestEffortCoverage()&lt;/a&gt;&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Precise coverage insurance
    &lt;ol&gt;
      &lt;li&gt;GC로 데이터를 잃지 않고 정확한 실행 횟수 등을 얻을 수 있지만 실행 성능 등에 영향을 받을 수 있다.
        &lt;ol&gt;
          &lt;li&gt;&lt;a href=&quot;https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage&quot;&gt;Profiler.startPreciseCoverage(callCount, detailed)&lt;/a&gt;&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best-effort coverage v8의 메커니즘을 활용하는 방식이다.&lt;/p&gt;

&lt;p&gt;첫 번째로 호출 카운터라고 불리는 요소를 이용한다.&lt;/p&gt;

&lt;p&gt;함수는 각각 v8의 ignition 인터프리터를 통해 호출되는데 함수가 호출될 때 마다 feedack vector의 호출 카운터를 증가시키도록 하는 방법이다.&lt;/p&gt;

&lt;p&gt;두 번재는 재활용 메커니즘은 “함수의 소스 범위를 알아내는 것이다.&lt;/p&gt;

&lt;p&gt;커버리지를 기록하고자 할 때 호출 카운터는 어떤 파일과 연관되는지 정보가 필요하다. 이때 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString&quot;&gt;Function.prototype.toString&lt;/a&gt;을 통해 함수의 위치를 알아낸 뒤, 부분 문자열을 추출해 내부적으로 함수의 시작과 끝 지점을 알 수 있다.&lt;/p&gt;

&lt;p&gt;따라서 Best Effort 커버리지 측정 방식은 실행 환경에서 사용되는 부산물(?) 들을 재활용해 특정하는 방식이기 때문에 성능상 영향이 적다.&lt;/p&gt;

&lt;p&gt;하지만 대략적인 커버리지를 알 수 있으며 GC나 기타 최적화에 의해 가려지기도 한다는 단점이 있다.&lt;/p&gt;

&lt;p&gt;Precise coverage는 Block 단위 커버리지라고도 불리는데, 이는 각각의 expression block에 대한 커버리지를 한다는 이야기가 된다. 예를 들어 if 절의 than 블럭과 else 블럭에 대한 각각의 측정을 한다는 것이다.&lt;/p&gt;

&lt;p&gt;Best effort도 호출 카운터를 이용하기에 오해할 수 있는데, 그때 사용되는 호출 카운터는 소스 범위만을 특정할 수 있어 블럭 단위의 정밀한 측정을 이야기하는 것은 아니다.&lt;/p&gt;

&lt;p&gt;Precise Coverage 측정은 v8 컴파일러가 AST를 분석하면서 Conditional Block을 Bytecode generation 할 때 IncBlockCounter 명령어를 집어넣는다. 이 명령어가 실행되냐에 따라 Call count를 도출할 수 있고, 이를 통해 블럭단위의 커버리지를 측정할 수 있는 것이다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;see-with-example&quot;&gt;See with example&lt;/h2&gt;

&lt;p&gt;이번 단락에서는 위에서 설명한 개념이 어떻게 실제로 동작하는지 볼 것이다.&lt;/p&gt;

&lt;p&gt;다음 함수에 대해&lt;/p&gt;

&lt;p&gt;커버리지를 측정한다고 가정해본다.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;V8 컴파일러 프론트엔드는 이 코드를 파싱하면서 AST를 구성할 것이다.&lt;/p&gt;

&lt;p&gt;아래 명령어를 통해 위 코드의 AST를 출력해보자.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./d8 --print-ast ~/workspace/chromium/playground/test.js&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;generating&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytecode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;function:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AST&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;FUNC&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KIND&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LITERAL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUSPEND&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;COUNT&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NAME&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PARAMS&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x158832470&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1588324f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DECLS&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARIABLE&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x158832470&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARIABLE&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1588324f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONDITION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PROXY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x158832470&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LITERAL&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BLOCK&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LITERAL&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// BLOCK&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;57&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// BLOCK &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ADD&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;66&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PROXY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x158832470&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PROXY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parameter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x1588324f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;b&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;AST의 Block으로 표현한 부분이 함수의 블럭, 조건 등에 의한 한 &lt;strong&gt;블럭들이&lt;/strong&gt; 될 것이다.&lt;/p&gt;

&lt;p&gt;그러면 위 AST를 통해 만들어진 결과물은(IR; Intermediate Representation)은 컴파일러의 백엔드로 전달되어 아래와 같은 바이트코드를 만들어 낼 것이다. (아마도 IR 표현에는 해당 로직이 포함되어 있을 것이다.)&lt;/p&gt;

&lt;p&gt;아래는 컴파일러가 해당 AST, IR을 전달받아 생성한 목적코드인 Bytecode (VM의 어셈블리어)다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node --print-bytecode --print-bytecode-filter=&quot;test&quot; ~/workspace/chromium/playground/v8_test.js&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;seokho&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;Dave&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/workspace/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chromium&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bytecode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bytecode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/workspace/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chromium&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;playground&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v8_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;js&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;generated&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bytecode&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x00a7d39a6811&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SharedFunctionInfo&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Bytecode&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Parameter&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Register&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Frame&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;OSR&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;urgency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Bytecode&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;385&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b88&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;IncBlockCounter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;398&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b8a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;LdaSmi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;403&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b8c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt;          &lt;span class=&quot;nx&quot;&gt;TestGreaterThan&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b8f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;06&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;JumpIfFalse&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xa7d39b8b95&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b91&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;IncBlockCounter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;417&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b93&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;                &lt;span class=&quot;nx&quot;&gt;LdaZero&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;425&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b94&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a9&lt;/span&gt;                &lt;span class=&quot;nx&quot;&gt;Return&lt;/span&gt;
         &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b95&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;02&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;IncBlockCounter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;437&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b97&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;             &lt;span class=&quot;nx&quot;&gt;Ldar&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a1&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;446&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b99&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;39&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt;          &lt;span class=&quot;nx&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;450&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xa7d39b8b9c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;@&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a9&lt;/span&gt;                &lt;span class=&quot;nx&quot;&gt;Return&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Constant&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mh&quot;&gt;0x00a7d39b8ba1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ByteArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;명령어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncBlockCounter&lt;/code&gt; 가 블록에 추가된 것을 확인할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncBlockCounter(slot)&lt;/code&gt; 명령어는 해당 블록 슬롯의 call counter를 증가시킨다.&lt;/p&gt;

&lt;p&gt;이 정보를  devtools protocol을 통해 결과로 가져온 것이 첫 단락에서의 커버리지 데이터인 것이다.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;p&gt;https://v8.dev/blog/javascript-code-coverage&lt;/p&gt;

&lt;p&gt;https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#method-startPreciseCoverage&lt;/p&gt;

&lt;p&gt;https://docs.google.com/document/d/1wCydi2HEZRF0skDeLb6CH0abZnTyVo5Vz5u-jhwi7es/mobilebasic&lt;/p&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="V8" /><category term="Javascript" /><category term="Jest" /><summary type="html">Motivation</summary></entry><entry><title type="html">CSS 삼각 함수를 배포했다</title><link href="https://blog.seokho.dev/ko/development/2022/12/20/css-trigonometric-functions.html" rel="alternate" type="text/html" title="CSS 삼각 함수를 배포했다" /><published>2022-12-20T00:00:01+00:00</published><updated>2022-12-20T00:00:01+00:00</updated><id>https://blog.seokho.dev/ko/development/2022/12/20/css-trigonometric-functions</id><content type="html" xml:base="https://blog.seokho.dev/ko/development/2022/12/20/css-trigonometric-functions.html">&lt;p&gt;CSS 삼각 함수를 배포했다.&lt;/p&gt;

&lt;p&gt;&lt;img width=&quot;402&quot; alt=&quot;Screenshot 2022-12-20 at 9 08 24 AM&quot; src=&quot;https://user-images.githubusercontent.com/18409763/208580491-09ba5854-aa6a-4149-b305-b9b5b271cfae.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Feature Entry: https://chromestatus.com/feature/5165381072191488&lt;/p&gt;

&lt;p&gt;7월쯤 시작한 Chromium에 CSS에 삼각함수를 구현하는 프로젝트 “CSSTrigonometricFunctions”를 마무리했다.&lt;/p&gt;

&lt;p&gt;취미개발로 주로 일요일과 출근시간 전, 퇴근 후 작업했다.&lt;/p&gt;

&lt;p&gt;CSS 삼각함수는 다음의 함수를 구현하는 프로젝트다.&lt;/p&gt;

&lt;p&gt;MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions#trigonometric_functions&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/sin&quot;&gt;sin()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/cos&quot;&gt;cos()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/tan&quot;&gt;tan()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/asin&quot;&gt;asin()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/acos&quot;&gt;acos()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/atan&quot;&gt;atan()&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/atan2&quot;&gt;atan2()&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;함수들은 &lt;a href=&quot;https://www.w3.org/TR/css-values-4/#trig-funcs&quot;&gt;css-values-4&lt;/a&gt; 스팩에 정의되어 있다.&lt;/p&gt;

&lt;p&gt;2018년에 W3C 스팩 초안이 만들어졌고, 2020년에 기능을 정의하는 삼각함수 챕터 ”11.4. Trigonometric Functions: sin(), cos(), tan(), asin(), acos(), atan(), and atan2()” 가 등장했다.&lt;/p&gt;

&lt;p&gt;올해 초 구현을 계획하다 리팩토링이 겹쳐 다른 작업들 위주로 개발하다 7월부터 실제 구현을 시작한 프로젝트로, &lt;a href=&quot;https://www.chromium.org/blink/launching-features/#implementations-of-already-defined-consensus-based-standards&quot;&gt;Chromium 정식 기능개발 과정&lt;/a&gt;인 &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/blink-dev/c/-c9p-Sq_gWg/m/C9eOR3oGAgAJ&quot;&gt;Intent to prototype&lt;/a&gt;과 &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/blink-dev/c/UiUVU722BbU/m/vQJy-qdpDAAJ&quot;&gt;Intent to Ship&lt;/a&gt; 그리고 3명의 커미터의 approved를 받아 stable로 전환하는 배포 CL이 머지되어 배포되었고, Chrome은 111 버전에 이 커밋이 포함되어 배포가 된다.&lt;/p&gt;

&lt;p&gt;Chrome  111 버전은 2월 9일부터 16일까지 beta를 거쳐 3월 1일부터 일반 사용자들에게 업데이트 된다.&lt;/p&gt;

&lt;p&gt;구현시 주요 내용은 삼각함수를 평가/처리하는 함수를 생성하고, 그 함수 내에서 각 함수별 처리를 추가하는 작업이 진행되었다. 삼각함수 하나당 하나의 CL(like PR)로 다뤄졌고, 관련한 WPT 테스트케이스들을 추가하게 되었다.&lt;/p&gt;

&lt;p&gt;atan2의 경우 현재 releative-length를 처리하는 것에 기술적인 이슈(특히, 파싱 타임에서 평가가 불가능해지는 점이)들이 존재해 relative 단위를 평가/처리 하지 않고, 그냥 자신의 값을 반환하게 구현했다.&lt;/p&gt;

&lt;p&gt;이는 주요 브라우저 엔진들인 webkit, gecko 도 동일하며, 관련한 이슈 이야기가 W3C/CSSWG 에서 논의되고 있다.&lt;/p&gt;

&lt;p&gt;이슈들 모아보기:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Crbug: &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=1392594&quot;&gt;https://crbug.com/1392594&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Webkit Bugzilla: &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=248513&quot;&gt;https://bugs.webkit.org/show_bug.cgi?id=248513&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Gecko Bugzilla: &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1802744&quot;&gt;https://bugzilla.mozilla.org/show_bug.cgi?id=1802744&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;W3C/CSSWG: &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/8169&quot;&gt;https://github.com/w3c/csswg-drafts/issues/8169&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Seokho Song</name><email>me@seokho.dev</email></author><category term="Chromium" /><category term="Chrome" /><category term="CSS" /><category term="Feature" /><category term="css-values-4" /><summary type="html">CSS 삼각 함수를 배포했다.</summary></entry></feed>