Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
V8 javascript engine for フロントエンドデベロッパー
Search
Taketoshi Aono(青野健利 a.k.a brn)
June 07, 2017
Programming
0
240
V8 javascript engine for フロントエンドデベロッパー
V8 javascript engineがjavascriptをどのように処理しているかの解説。
Taketoshi Aono(青野健利 a.k.a brn)
June 07, 2017
Tweet
Share
More Decks by Taketoshi Aono(青野健利 a.k.a brn)
See All by Taketoshi Aono(青野健利 a.k.a brn)
document.write再考
brn
6
3.1k
Parsing Javascript
brn
14
9.4k
JSON & Object Tips
brn
1
540
CA 1Day Youth Bootcamp for Frontend LT
brn
0
1k
Modern TypeScript
brn
2
850
javascript - behind the scene
brn
3
790
tc39 proposals
brn
0
940
プロダクト開発とTypeScript
brn
8
3k
React-Springでリッチなアニメーション
brn
1
750
Other Decks in Programming
See All in Programming
Spinner 軸ズレ現象を調べたらレンダリング深淵に飲まれた #レバテックMeetup
bengo4com
1
230
AIフル活用時代だからこそ学んでおきたい働き方の心得
shinoyu
0
130
dchart: charts from deck markup
ajstarks
3
990
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
Lambda のコードストレージ容量に気をつけましょう
tattwan718
0
120
副作用をどこに置くか問題:オブジェクト指向で整理する設計判断ツリー
koxya
1
610
CSC307 Lecture 09
javiergs
PRO
1
830
AIによる開発の民主化を支える コンテキスト管理のこれまでとこれから
mulyu
3
240
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
370
AI時代の認知負荷との向き合い方
optfit
0
160
責任感のあるCloudWatchアラームを設計しよう
akihisaikeda
3
170
【卒業研究】会話ログ分析によるユーザーごとの関心に応じた話題提案手法
momok47
0
200
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.6k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
WCS-LA-2024
lcolladotor
0
450
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Rails Girls Zürich Keynote
gr2m
96
14k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.6k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
410
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
0
140
Paper Plane (Part 1)
katiecoart
PRO
0
4.1k
Transcript
V8 javascript engine
せ: @brn (ꫬꅿ⨳ⵃ) 耵噟: ؿٗٝزؒٝسؒٝآص،٥ط؎ذ؍ـؒٝآص، ⠓爡: Cyberagent ،سذؙأةآؔRightSegment٥AI Messenger ـؚٗ:
http://abcdef.gets.b6n.ch/ Twitter: https://twitter.com/brn227
V8הכ V8הכGoogleָ㹋鄲׃javascriptؒٝآٝדծ Google Chromeךjavascriptؒٝآٝח䱰欽ׁגְתׅկ
V8הכ V8ך暴䗙 • 넝鸞 • Hidden Classהְֲⰻ鿇㘗ءأذي • Inline Caching
• ⚅➿ⴽך؝ٖٝؕٝز٥؎ًؙٝٔٝةٕGC • غ؎ز؝٦س؎ٝة٦فٔةⰻ詿2016䎃劣 • 㼎䘔CPUכMipsծArmծX64ծX86٥7
V8הכ 劤傈כծ javascriptָا٦أ؝٦سַ㹋遤ׁתדך麣ךծד ֹֽ铡僇׃תׅկ ծ♧א♧אך갪湡ָֽדꞿְ儗ֶ鑧דֹג׃ת ֲ״ֲזⰻ㺁ךזךדծ➙㔐כ謬ֻ䎢ֻ鑧׃״ֲה䙼ְתׅկ ⰻ㺁ָ崮ְַ׃תׇָ׀㺁饘ְֻׁկ⯜顑✲갪
V8 Code base V8ך؝٦سك٦أך遤侧כծا٦أؿ؋؎ٕךדծ 秈108♰遤،٦ؗذؙثٍ㔿剣ך؝٦سろ֮תׅկ 鎉铂כC++ד鎸鶢ׁגֶծوؙٗ㿊קו֮תׅկ 铣ך鳞ְ…
V8ך㹋遤ך崧 Source AST Bytecode Graph Assembly
Parsing ת׆ծV8כا٦أ؝٦سػ٦أ׃גASTח㢌䳔׃תׅկ ASTהכAbstractSyntaxTreeך殛ד䬄韋圓俑加הㄎלתׅկ
Abstract Syntax Tree if (x) { x = 100 }
Abstract Syntax Tree IF CONDITION THEN BLOCK EXPRESSION STATEMENT ASSIGN
VAR PROXY (X) LITERAL (100) if (x) { x = 100
Parsing ׃ַ׃ծWebل٦آְة؎ىؚٝדjavascriptⰋ鿇 ػ٦أ׃גخٔ٦⡲ךכ鹼ֻזְד׃׳ֲַ
Parsing 鹼ְדׅկ זךדծV8כ鹼䒀ػ٦أ遤ְתׅկ
Lazy Parsing function x() {return 1;} FUNCTION(X)
Lazy Parsing function x() {return 1;} x() FUNCTION NAME (x)
RETURN LITERAL(1)
Lazy Parsing ֿך״ֲחծV8כ㹋ꥷחㄎן⳿ׁתדػ٦أ鹼䒀׃תׅկ ֿך鹼䒀כꟼ侧⽃⡘ד遤תׅկ
PreParsing ׃ծ㸣Ⰻחׅץג鹼䒀ػ٦أֽׅדכ֮תׇկ v8::internal::PreParserؙٓأָ♧䏝ꟼ侧ך،ؐزٓ؎ٝػ٦ أ׃תׅկ ֿח״גծ • ✲ך俑岀ؒٓ٦ثؑحؙ • ꟼ侧ךأ؝٦ف欰䧭 瘝遤ְתׅկ
Dive into Parsing V8ךParsingחאְגכֽד涪邌דְֹֻ帾ְ㉏겗דծ https://docs.google.com/presentation/d/1b- ALt6W01nIxutFVFmXMOyd_6ou_6qqP6S0Prmb1iDs/present? slide=id.p ח涪罏ךأٓ؎سָ֮תׅךדծ撑կ
Abstract Syntax Tree ׁגծֿד㹋ꥷחػ٦أ遤גְֹתׅկ זחծV8כ䩛剅ֹדػ٦؟٦鎸鶢׃גֶծyaccװlexהְ ؝ٝػ؎ٓ؝ٝػ؎ٓⵃ欽׃גְתׇկ ⱄ䌓♴꣬圓俑鍑匿岀דػ٦أ׃גְתׅկ
AST Rewriter V8ךASTחꟼ׃ג׳ה涯ְ㹋鄲鋅אֽךדծ 腜麣דָׅծ铡僇׃תׅկ
AST Rewriter javascriptך圓俑דծSpreadؔلٖ٦ة٦הְֲ圓俑ָ֮ת ׅկ var x = [1,2,3]; var y
= […x]; V8כֿך圓俑AltJSךزٓٝأػ؎ٓך圫חⰋֻⴽך圓俑ח 剅ֹ䳔ִג׃תְתׅկ
AST Rewriter do { $R = []; for ($i of
x) %AppendElement($R, $i); $R } // src/parsing/parser.cc ֿך״ֲחծ瘝⣣ךdo圓俑הfor-of圓俑ח剅ֹ䳔ִ ג׃תְתׅկ
Abstract Syntax Tree ׁגծػ٦أָ㸣✪׃ծASTך欰䧭ָ㸣✪׃ת׃կ V8ךASTד暴䗙涸זךכծ 㹋ꥷך鎉铂圓鸡הوحث׃זְAST欰䧭ׅ挿דׅկ וְֲֲֿהַהְֲה…
Abstract Syntax Tree var x = 100
Abstract Syntax Tree var EXPRESSION STATEMENT CALL RUNTIME [IniOalizeVarGlobal] LITERAL
(x) LITERAL (100) x 100 ?
Abstract Syntax Tree V8כRuntimeㄎן⳿׃瘝ךC++ךㄎן⳿׃ծ ⟎䟝ךASTה׃גAST欰䧭儗挿ד欰䧭׃ג׃תְתׅկ
AST to Bytecode ASTך欰䧭ָ㸣✪׃֮הכծ 欰䧭׃ASTַBytecode欰䧭׃תׅկ V8ךBytecodeכ劤䔲ח1Byteד邌植ׁ⟎䟝ㄏ⟀דׅկ ׃גծךBytecode㹋遤ׅVMIgnitionהㄎןתׅկ
Igniton V8חכIgnitionהㄎלBytecode؎ٝة٦فٔةָ㹋鄲ׁ גְתׅկ 㹋כֿך؎ٝة٦فٔةכ剑鵚㹋鄲ׁלַךךדծ ׳התדכASTַ،إٝـٔ湫ח⳿⸂׃גְת׃ կ
Igniton Ignitionכٖآأةك٦أךغ؎ز؝٦س؎ٝة٦فٔةדծCPUךٖآ أةח㹋ꥷח⦼ⶴ➰ֽג㹋遤׃תׅկ IgnitionכBytecodeHandlerהㄎלغ؎ز؝٦سⳢ椚ꟼ侧✮欰䧭 ׃גֶֹծغ؎ز؝٦سַꂁך؎ٝرحؙأ《䖤ծ ך؎ٝرحؙأח欰䧭ׁ،إٝـٓⶴ䔲גגծBytecodeךꂁ 如ղ䊡㔐׃זָծ㼎䘔ׅ؎ٝرحؙأך،إٝـٓㄎן⳿׃ ؝٦س㹋遤׃תׅկ
Igniton זקוծַ
// 擬似的なjavascriptコード ! var Bytecodes = [0,1,2,3] var index =
0; function dispatch(next) { BytecodeHandlers[next](); } const BytecodeHandlers = { ['0']() {...; dispatch(Bytecodes[index++])}, ['1']() {...; dispatch(Bytecodes[index++])}, ['2']() {...; dispatch(Bytecodes[index++])}, ['3']() {...; dispatch(Bytecodes[index++])} } const firstBytecode = Bytecodes[index++]; BytecodeHandlers[firstBytecode](firstBytecode);
Igniton Dispatch Table 00 01 02 04 08 0f 10
10 Node Node Node MachineCode MachineCode IGNITION_HANDLER Entry Function(Machine Code) グラフからコードを生成 生成したコードを、 DispatchTableの対応する バイトコードのインデックスへ 登録
Igniton Ignitionכغ؎ز؝٦سך欰䧭ASTַ遤ְתׅկ V8כAST䊡㔐ׅ倯岀ה׃גծv8::internal::AstVisitor<Subclass> הְֲ㛇䎿ؙٓأ欽䠐׃גְתׅկ AstVisitorךせך鸐ծVisitorػة٦ٝⵃ欽׃גAST䊡㔐׃ծⳢ 椚遤גְֹתׅկ
Visitor Pattern class Visitor { void Visit(Ast* ast) { ast->Accept(this);
} void VisitXXX(XXX* ast) { ast->property->accept(this); } } class Ast(XXX) { void Accept(Visitor* visitor) { visitor->VisitXXX(this) } }
Igniton 欰䧭ׁBytecodeכBytecodeArrayהㄎלꂁח呓秛ׁת ׅկ 㹋遤儗חכֿךBytecodeArrayוג㹋遤ֿׅהחזתׅկ
Igniton Dispatch Table Entry Function(Machine Code) BytecodeArray Dispatch Tableから対応するHandlerを取り出して実行 0
1 3 4 5 6 7 8 8 6 1
Code Generation V8חכְֻאַך،إٝـٓ欰䧭皘䨽ָ֮תׅկ 㣐ⴽׅה⟃♴חזתׅկ CodeStub Builtins Runtime BytecodeHandler
Code Generation Bytecodeַ،إٝـٓ㹋遤ׅךכַת׃ָծ Bytecodeַ㼎䘔ׅ،إٝـٓכוך״ֲח欰䧭׃גְךד׃׳ֲַ BytecodeHandlerהכוך״ֲזךזךד׃׳ֲַ
IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {! Node* value = GetAccumulator();! // Accumulatorの値を取得! Node*
relative_jump = BytecodeOperandUImmWord(0);! // 引数のoperandを取得! Label if_true(this), if_false(this);! BranchIfToBooleanIsTrue(value, &if_true, &if_false);! // valueがtrueならif_true、falseならif_false! Bind(&if_true);! Dispatch();! Bind(&if_false);! // operandのbytecodeまでjump! Jump(relative_jump);! }!
Code Generation ֿծ㹋כ㹋ꥷחכ㹋遤ׁתׇկ וְֲֲֿהַהְֲהծֿך؝٦سכ㹋遤ׁהծ 㹋遤✮㹀ךGraph欰䧭ֽׅדׅկ
Code Generation 㹋ꥷךC++؝٦سך崧הכ麩ֲDSL鎉铂דؚٓؿָ㹋鄲ׁגְתׅկ
IGNITION_HANDLER(ForInContinue, InterpreterAssembler) {! ...! Branch(WordEqual(index, cache_length), &if_true, &if_false);! Bind(&if_true);! {!
SetAccumulator(BooleanConstant(false));! Goto(&end);! }! Bind(&if_false);! {! SetAccumulator(BooleanConstant(true));! Goto(&end);! }! ...! }!
Code Generation דכ㹋ꥷח،إٝـٓ⳿⸂ׅךכוֿזךַהְֲהծ MacroAssemblerהְֲؙٓأָך䕵ⶴ䬐גְתׅկ MacroAssemblerכ؎ٝة٦ؿؑ٦أכ،٦ؗذؙثٍ杝甧דָׅծך ⰻ鿇דㄎדְAssemblerؙٓأָぐ،٦ؗذؙثٍ㔿剣ך؝٦س ⳿⸂׃תׅկ V8דכ㹋ꥷmasmהְֲفٗػذ؍せדMacroAssemblerָ걼⳿׃תׅկ
#define __ ACCESS_MASM(masm)! ! static void Generate_StackOverflowCheck(...) {! ! __
LoadRoot(kScratchRegister, Heap::kRealStackLimitRootIndex);! __ movp(scratch, rsp);! ! __ subp(scratch, kScratchRegister);! __ sarp(scratch, Immediate(kPointerSizeLog2));! ! __ cmpp(scratch, num_args);! ! __ j(less_equal, stack_overflow, stack_overflow_distance);! }!
Code Generation ׃ג剑穄涸חכծ GraphResolver㹋鄲׃CodeGeneratorؙٓأָGraph䊡㔐׃גծ MacroAssembler穗歋דAssemblerㄎן⳿׃ծ،إٝـٓ⳿⸂׃תׅկ
Code Generation ׃ծMacroAssemblerכ剑穄涸ז؝٦س⳿⸂ד֮גծ Graphⰻח⯋חז䬄韋⻉ׁؔل؝٦سָ㙵鴥תתׅկ ⟃♴ךꥡ㾴דծ،٦ؗذؙثٍ㔿剣ךGraphָ欰䧭ׁתׅկ • CodeStubAssembler • CodeAssembler •
RawMachineAssembler • MachineOperatorBuilder ♴ח遤ֻקוⰧ⡤涸זㄏ⟀חזתׅկ
Code Generation e.x Load CodeStubAssembler::Load CodeAssembler::raw_assembler()->Load() RawMachineAssembler::Load AddNode(MachineAssembler::Load()) Graph Leaf
Node
Optimization ׁגծֿדjavascript㹋遤ׅ彊⪒ָדֹת׃կ ׃ַ׃ֿד넝鸞זjavascript㹋遤ֿׅהָדֹד׃׳ֲַ 鸐䌢ծ⹛涸鎉铂ד֮javascriptכ㘗ח暴⻉׃Ⳣ椚遤ֲֿהָד ֹתׇկ ֿדծV8כ㹋遤儗ח暴ח걼籕ח㹋遤ׁ皘䨽ך㘗暴㹀ծ؝٦ س䊴׃剏ִתׅկֿJIT(آٍأز٥؎ٝ٥ة؎ي)؝ٝػ؎ٓ הㄎןתׅկ
Optimization V8ך剑黝⻉חכ㣐ֹֻⴓֽג3珏겲֮תׅկ • Hidden Class • Inline Caching • TurboFan
Hidden Class javascriptחכאְ剑鵚תדclassכ֮תׇד׃կ ך➿prototypeהְֲ➬穈ד毟⡂ؙٓأⱄ植׃גְת׃կ תծ圓鸡⡤֮תׇկ 㘗ָזְךדծ • ؔـآؙؑزךًاحسㄎן⳿ׅ • فٗػذ؍ח،ؙإأׅկ
ֿךⳢ椚ך穠卓כ䌢ח♧㹀הכꣲתׇկ
Hidden Class ֿדV8כؔـآؙؑزךٖ؎،ؐزח岣湡׃ת׃կ ⢽ִלծ function Point(x, y) { this.x =
x; this.y = y }; var point = new Point(1, 1); ֿPoint㘗ה׃ג钠陎ׅחⰻ鿇ד㘗䭯גְתׅկ
Map V8דכ • ずׄفٗػذ؍せ • ずׄ㘗 • ずׄ갫䎷 ד㹀纏ׁ㜥さכずؙׄٓأהזׅ״ֲחׅծMapהְ ֲ嚊䙀䭯鴥ת׃կ
ֿךMapכؔـآؙؑز欰䧭儗ծؙٓأד֮ל؝ٝأزؙٓة㹋 遤㸣✪儗ח欰䧭ׁծؔـآؙؑزךٖ؎،ؐز⥂䭯׃תׅկ ずׄ圓鸡ד֮לծずׄMapָⰟ剣ׁתׅկ
Map function Point(x, y) { this.x = x; this.y =
y; } Map FixedArray [ {a: {offset: 0}}, {b: {offset: 1}} ]
Map ׃ַ׃ծjavascriptדכفٗػذ؍ָ㢌⻉ֿׅהכ傈䌢蘠궢✲דׅկ ך㜥さכוֲׅךד׃׳ֲַ
Map Transition فٗػذ؍ך㟓幾ח״גؔـآؙؑزךٖ؎،ؐزָ㢌⻉׃㜥 さծV8כtransitionהְֲⳢ椚遤גծ麓ךMap竰䪫׃倜 זMap欰䧭׃תׅկ
Map Transition function Point(x, y) { this.x = x; this.y
= y; } Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}}, transiOon: {address: …} ] var x = new Point(1, 1); x.z = 1; Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}}, {z: {offset: 2}} ] transition
Inline Caching Inline Cachingהכفٗػذ؍ٕحؙ،حف넝鸞⻉ׅך 剑黝⻉䩛岀דׅկ
class X {add() {return 1}}! class Y {add() {return 2}}!
var m = [new X(), new X(), new Y()];! for (let i = 0; i < m.length; i++) {! m[i].add();! }! !
Inline Caching 初回 V8 add Receiver Map Cached address 1.
Search 2. Check 4. Cache 3. Call
Inline Caching 二回目以降 V8 add Receiver Map Cached address 1.
Search and Call
Inline Caching Inline Cachingחכ⟃♴ך4אך朐䡾ָ֮תׅկ • Premonomorphic • Monomorphic • Polymorphic
• Megamorphic
Premonomorphic Premonomorphicהכⴱ㔐ךICךة؎ىؚٝך朐䡾ד鏣㹀ׁתׅկ ֿךة؎ىؚٝדכ剑鸞ךػأדכזֻ⡚鸞ךStubָ؝٦سח鏣㹀 ׁתׅկ
Monomorphic MonomorphicהכReceiverך㘗ָ♧㹀ך؛٦أך㜥さךICדׅկ ֿך㜥さכ♧אךٍؗحءُדׅךדծ剑鸞ך؛٦أחזתׅկ
Polymorphic PolymorphicהכReceiverך珏겲ָ珏겲⟃♳ך؛٦أד鏣㹀ׁת ׅկPolymorphicכぐMapַٕ٦فדٍؗحءُ䱱׃⳿ׅךדծ Monomorphic״כ⡚鸞דָׅծICז׃״כ黓ַח넝鸞דׅկ
Megamorphic Megamorphicכ֮תחىأوحثָ㢳ְ㜥さך؛٦أדׅկ ٍؗحءׁُ؝٦سعحءُذ٦ـַٕ䱱稊׃תׅկ ֿך䱱稊כׅץג،إٝـٓד遤תׅկ
(Load/Store)IC_Miss LoadIC_MissהStoreIC_MissכICחوحث׃זַ㜥さַծⴱ㔐ח ㄎלծC++ךٓٝة؎ي穗歋׃גؔـآؙؑزךفٗػذ؍ 《䖤׃תׅկ
(Load/Store)IC_Miss 二回目以降 V8 add Receiver (y) Map Cached address (x)
1. Search 2. Compare Map x !== y 3. (Load/Store)IC_Miss
Optimized Compilation V8כ䌢ח剑鸞ך؝٦س⳿⸂ֽׅדכ֮תׇկ ⴱ㔐כ䗳׆ծBytecode穗歋ד㹋遤ׁGenericז؝٦سָ㹋遤ׁ ծRuntimeㄎן⳿׃㢳ֻ⡚鸞ז؝٦سָ㢳ְדׅկ ךծ㹋遤湊鋔׃ծقؽ٦ח㹋遤ׁ皘䨽剑黝⻉׃תׅկ
Hot Spot V8ָ⚺ח湊鋔׃גְךָծ • ٕ٦ف • ꟼ侧ך㹋遤 דׅկ
Loop Tracing قؽ٦זٕ٦ف鋅אֽהծV8ך鿇ⴓ剑黝⻉׃؝٦سד 縧ֹ䳔ִתׅկ ֿךꥷծV8כOnStackReplacementהְֲ䩛岀ⵃ欽׃גٕ٦ف ؝٦س剑黝⻉׃תׅկ
On Stack Replacement for (let i = 0; i <
10000; i++) { doSomething(i); } JumpLoop LoopHeader SlowCode FastCode PC(فؚٗٓيؕؐٝة)縧ֹ䳔ִ
Function Call Tracing ꟼ侧ㄎן⳿׃ך㜥さכծIgnitionָ欰䧭ׅReturn Bytecodeך BytecodeHandlerⰻדㄎן⳿׃㔐侧鎘庠׃ծ׃ְֹ⦼馄ִ㜥 さכInterrupt遤גծꟼ侧؝ٝػ؎ٕ׃ꟼ侧ךBodyⰅ剏ִ תׅկ
Function Interruption function Y() { … } RETURN OP Replace
Body しきい値チェック
TurboFan V8כ؝٦سGraphַ欰䧭׃תׅկ ךծׅץגך剑黝⻉Graphח㼎׃ג遤ծ خٔ٦ך協ⴘ瘝ךؚٓؿ剑黝⻉遤תׅկ ֿך剑黝⻉ػ؎فٓ؎ٝךֿהTurboFanהㄎןתׅկ
TurboFan TurboFanך剑黝⻉ٔأزדׅկ • Loop peeling / Loop elimination • Escape
analysis • Lowering • Effect and control linearize • Dead code elimination • Control flow optimization • Memory optimization
Deoptimization 剑黝⻉׃؝٦سָ䌢ח㹋遤〳腉הכꣲתׇկ Mapָ㢌ծ侧⦼ָoverlow׃ծ0ꤐ皾؝٦س㹋遤ׁ… ך㜥さծV8כ膴剑黝⻉遤גծ剑黝⻉ׁךBytecodeח䨱 תׅկ
Pipeline OpOmize Assembler TurboFan Source AST Parser Bytecode Graph IgniOon
Compile Optimization Deoptimization
תה ⟃♳ָV8ָا٦أ؝٦سַ堣唒铂欰䧭ׅ䊨玎הזתׅկ ➙㔐כGCחכ鍗גְזְדָׅծ V8חכGC䊨㣗ָ㢳ְךדծ莆ך֮倯כמ鋅גגֻׁ ְկ ׀幠耮ָ֮הֲ׀ְׂת׃կ