Design: ๋ฐ์ดํ„ฐ JS/WASM ์ปจํ…์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•

์— ๋งŒ๋“  2018๋…„ 09์›” 12์ผ  ยท  18์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: WebAssembly/design

์•ˆ๋…•ํ•˜์„ธ์š”,

Float32Array ๋ฒ„ํผ์— 1024๊ฐœ์˜ f32 ๊ฐ’์ด ์ €์žฅ๋˜์–ด ์žˆ๊ณ  WASM ๊ธฐ๋ฐ˜ DSP ์ฝ”๋“œ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ด…์‹œ๋‹ค. :)

๋‚˜๋Š” ์—ฌ์ „ํžˆ WebAssembly์— ์ต์ˆ™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ์ˆซ์ž ๊ฐ’๋งŒ ๋‚ด๋ณด๋‚ธ WASM ํ•จ์ˆ˜์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์˜๋ฏธ๊ฐ€ ์žˆ์œผ๋ฉฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋‚˜๋„ ๊ทธ๊ฑฐ ๊ดœ์ฐฎ์€๋ฐ...

๋”ฐ๋ผ์„œ 1024๊ฐœ์˜ ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด .memory ์ง์ ‘ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ข‹๋‹ค:

const mem = exports.memory.buffer;
const F32 = new Float32Array(mem);
F32[0] = 31337.777;

์ด๊ฒƒ์€ ์žฌ๋ฏธ์žˆ์ง€๋งŒ ๋ชจ๋“  ๊ฐ’์„ ํ• ๋‹นํ•˜๋ ค๋ฉด ๋ชจ๋“  ๊ฐ’์„ ๋ฐ˜๋ณตํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธ€์Ž„, ์–ด๋–ป๊ฒŒ ๋ณด๋ฉด ์„ฑ๋Šฅ โ€‹โ€‹๋ฉด์—์„œ ์ž˜๋ชป๋œ ๋Š๋‚Œ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ impl์„ ๊ธฐ๋Œ€ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋ฅผ ์œ„ํ•ด ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด. ์ถ”์ฒœ ์˜ˆ ํ‚ค data ์—์„œ memoryDescriptor ์˜ ์ธ์ˆ˜ WebAssembly.Memory ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์ƒ์„ฑ์ž ArrayBuffer .

์ž, ๊ทธ๋Ÿผ ์ €๋Š” WASM ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ•˜๊ณ  WASM impl์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋งˆ์ˆ ์ฒ˜๋Ÿผ ๊ฒฐ๊ณผ ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ๋‹ค์‹œ ์“ฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ DSP ๋ฃจํ”„ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋‚ด๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ•œ WASM ์ฝ”๋“œ ๋‚ด๋ถ€์— ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด์ œ JS ์ปจํ…์ŠคํŠธ๋กœ ๋Œ์•„๊ฐ„ ํ›„ ๋ชจ๋“  ๊ฐ’์„ ์ฝ๊ณ  ๋˜ ๋‹ค๋ฅธ JS ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ ํ‘œํ˜„์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋ฐ˜๋ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ป๊ฒŒ ๋“  ๋‚˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์ž„ํ”Œ์„ ๊ธฐ๋Œ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชฉ์ ์œผ๋กœ๋„ ์ฐธ์„ํ•ฉ๋‹ˆ๋‹ค. memory.read(Float32Array) ์™€ ๊ฐ™์€ ๊ฒƒ์ด ๋ฒ„ํผ ๋ฐ์ดํ„ฐ๋ฅผ Float32Array ๋ฐ˜ํ™˜ํ•˜์—ฌ ํฌ์ธํ„ฐ์™€ ๋ฐ˜๋ณต ๋ฏธ๋กœ๋ฅผ ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?
๋ฐฉ๊ธˆ ๊ฐ„๊ณผํ•œ ๋งŽ์€ ์–‘์˜ ๋ฐ์ดํ„ฐ๋ฅผ WASM๊ณผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.
์•„๋ก 

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

JavaScript์™€ WebAssembly ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ• ์ง€ ์•„๋‹ˆ๋ฉด WebAssembly๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์œ ํ•˜๋„๋ก ํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๋ ค๋ฉด for ๋ฃจํ”„๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  TypedArray.prototype.set() ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

let instance = ...;
let myJSArray = new Float32Array(...);
let length = myJSArray.length;
let myWasmArrayPtr = instance.exports.allocateF32Array(length);
let myWasmArray = new Float32Array(instance.exports.memory.buffer, myWasmArrayPtr, length);

// Copy data in to be used by WebAssembly.
myWasmArray.set(myJSArray);

// Process the data in the array.
instance.exports.processF32Array(myWasmArrayPtr, length);

// Copy data out to JavaScript.
myJSArray.set(myWasmArray);

WebAssembly๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์œ ํ•˜๋Š” ๊ฒฝ์šฐ WebAssembly.Memory ๋ฒ„ํผ์— ๋Œ€ํ•œ ๋ณด๊ธฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ JavaScript ํ•จ์ˆ˜์—๋„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

let instance = ...;
let length = ...;
let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

// No need to copy data back to JavaScript, just use myArray directly.

๋˜ํ•œ embind ์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  18 ๋Œ“๊ธ€

JavaScript์™€ WebAssembly ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ• ์ง€ ์•„๋‹ˆ๋ฉด WebAssembly๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์œ ํ•˜๋„๋ก ํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๋ ค๋ฉด for ๋ฃจํ”„๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  TypedArray.prototype.set() ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

let instance = ...;
let myJSArray = new Float32Array(...);
let length = myJSArray.length;
let myWasmArrayPtr = instance.exports.allocateF32Array(length);
let myWasmArray = new Float32Array(instance.exports.memory.buffer, myWasmArrayPtr, length);

// Copy data in to be used by WebAssembly.
myWasmArray.set(myJSArray);

// Process the data in the array.
instance.exports.processF32Array(myWasmArrayPtr, length);

// Copy data out to JavaScript.
myJSArray.set(myWasmArray);

WebAssembly๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์œ ํ•˜๋Š” ๊ฒฝ์šฐ WebAssembly.Memory ๋ฒ„ํผ์— ๋Œ€ํ•œ ๋ณด๊ธฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ JavaScript ํ•จ์ˆ˜์—๋„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

let instance = ...;
let length = ...;
let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

// No need to copy data back to JavaScript, just use myArray directly.

๋˜ํ•œ embind ์™€ ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™€, @binji๋‹˜ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋ฉ‹์ง€๋„ค์š”. ์ œ๊ฐ€ ์ฐพ๋˜ ๋ฐ”๋กœ ๊ทธ ์ œํ’ˆ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์‹œ๊ฐ„์„ ๋‚ด์–ด ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ๋„ ๋งค์šฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜ ์ €๋…์— ์‹œ๋„ํ•˜๊ณ  Loader impl์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ฐœ์„  ์‚ฌํ•ญ์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. https://github.com/AssemblyScript/assemblyscript์—์„œ WASM๊ณผ ์ธํ„ฐํŽ˜์ด์Šคํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.

์ด์™€ ๊ด€๋ จํ•˜์—ฌ webassembly.org์—์„œ ๋ฌธ์„œ๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

https://webassembly.org/docs/web/

๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๊ธฐ๊บผ์ด ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ฒ ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ์ƒ๊ฐ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory

@binji ์ฃผ์ œ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด ์•„์ง ์•Œ์ง€ ๋ชปํ•œ๋‹ค๋ฉด https://github.com/torch2424/wasmBoy๋ฅผ ์ข‹์•„ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํ”„๋กœ์ ํŠธ๋Š” for ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ROM ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์˜ ์ด์ ์„ ์–ป์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ด€๋ จํ•˜์—ฌ webassembly.org์—์„œ ๋ฌธ์„œ๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ๊ณผ ํ•จ๊ป˜ webassembly.org๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์žˆ๋Š” ๋ฌธ์„œ๋Š” ์—ฌ์ „ํžˆ ์žˆ์ง€๋งŒ ์‚ฌ์–‘ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋Š” ํ›จ์”ฌ ์ตœ์‹ ์ด๊ณ  ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค.

๋” ๋งŽ์€ ์›น ๊ฐœ๋ฐœ์ž๊ฐ€ webassembly.org๋ณด๋‹ค ํ•ด๋‹น ์‚ฌ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด MDN์— ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๊ณ  ๋” ๋‚˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚˜ ์•„์ง ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด ์•Œ์ง€ ๋ชปํ•œ๋‹ค๋ฉด https://github.com/torch2424/wasmBoy๋ฅผ ์ข‹์•„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ, @torch2424๋ฅผ ์••๋‹ˆ๋‹ค. :-) ์ €๋งŒ์˜ wasm ๊ธฐ๋ฐ˜ ๊ฒŒ์ž„๋ณด์ด ์—๋ฎฌ๋ ˆ์ดํ„ฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/binji/binjgb

๋” ๋งŽ์€ ์›น ๊ฐœ๋ฐœ์ž๊ฐ€ webassembly.org๋ณด๋‹ค ํ•ด๋‹น ์‚ฌ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ผ๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด MDN์— ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๊ณ  ๋” ๋‚˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ๋ฐค ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฒŒ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ณต๊ฐœ๋˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ˆ, @torch2424๋ฅผ ์••๋‹ˆ๋‹ค. :-) ์ €๋งŒ์˜ wasm ๊ธฐ๋ฐ˜ ๊ฒŒ์ž„๋ณด์ด ์—๋ฎฌ๋ ˆ์ดํ„ฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/binji/binjgb

ํ•˜ํ•˜, ๋ฉ‹์ง€๋‹ค! ๋ฐํ”„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์‹œ๋„ํ•ด ๋ณด์„ธ์š” :) ์—๋ฎฌ๋ ˆ์ดํ„ฐ๋Š” Zelda - Link's Awakening์—์„œ ์นผ์„ ์–ป์„ ๋•Œ ์ถฉ๋Œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (ํ•ด๋ณ€์—์„œ) ;))

๋‚˜๋Š” wasmBoy์—์„œ๋„ ์ถฉ๋Œ์„ ๊ณ ์น  ์‹œ๊ฐ„์„ ์ฐพ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. :)

์ด๋ด! wasmboy๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค! ๐Ÿ˜„ ๋„ค, @binji ์˜ ์—๋ฎฌ๋ ˆ์ดํ„ฐ๊ฐ€ ํ™•์‹คํžˆ ๋” ์ •ํ™•

ํ”ผ๋“œ๋ฐฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ช‡ ๊ฐ€์ง€ ๋ฒ„๊ทธ๋ฅผ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค.
https://github.com/torch2424/wasmBoy/issues/141 - ๋ฉ”๋ชจ๋ฆฌ ์ „๋‹ฌ
https://github.com/torch2424/wasmBoy/issues/142 - Zelda Crash(์Šคํฌ๋ฆฐ์ƒท๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค)

์–ด์จŒ๋“ , ๋Œ€ํ™”/๋ฌธ์ œ๋ฅผ ํƒˆ์„ ์‹œํ‚ค๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ๋‚ด๊ฐ€ ์—ฐ ๋ฌธ์ œ๋กœ ๋„˜์–ด๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ”ผ๋“œ๋ฐฑ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ˜„

WebAssembly๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ์œ ํ•˜๋Š” ๊ฒฝ์šฐ WebAssembly.Memory ๋ฒ„ํผ์— ๋Œ€ํ•œ ๋ณด๊ธฐ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ JavaScript ํ•จ์ˆ˜์—๋„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์ฃผ์˜ ์‚ฌํ•ญ: WebAssembly ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋Š˜๋ฆฌ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ฒ„ํผ์— ๋Œ€ํ•œ ๋ณด๊ธฐ๊ฐ€ ๋ฌดํšจํ™”๋ฉ๋‹ˆ๋‹ค. WebAssembly ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ํ˜ธ์ถœ ์ดํ›„์— ์ง€์†๋˜๋Š” ๋ทฐ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

@binji ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•  ๋•Œ AssemblyScript ์ธก์— ๋ฌด์—‡์„ ๋„ฃ๋Š”์ง€ ์•Œ๋ ค

let myWasmArrayPtr = instance.exports.allocateF32Array(length);

๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์“ฐ๊ณ  ์ž‘๋™ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ธ์ง€ ์•Œ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

export function allocateF32Array(length: usize): usize {
    return memory.allocate(length * sizeof<f32>());
}

memory.free() ๋กœ ํ•ด์ œํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ AS ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•˜๊ณ  ๋ฐฐ์—ด์„ JS ์ธก์— ์ „์†กํ•œ ํ›„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@fmkang @binji๊ฐ€ ์„ค๋ช…ํ•œ ๋‚ด์šฉ์€ JS ์ธก์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค(ํ‹€๋ฆฐ ๊ฒฝ์šฐ ์ˆ˜์ •ํ•ด ์ฃผ์„ธ์š”).

Typed Arrays๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Wasm Array Buffer์™€ ํ•จ๊ป˜ set() ์„ ์‚ฌ์šฉํ•˜์—ฌ JS ์ธก์—์„œ WASM ๋ฉ”๋ชจ๋ฆฌ์— ํšจ์œจ์ ์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Wasm/AS ๋‚ด๋ถ€์—์„œ Wasm ๋ฉ”๋ชจ๋ฆฌ์— ์“ฐ๊ธฐ, ์—ฌ์ „ํžˆ ํ‘œ์ค€ for ๋ฃจํ”„ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: https://github.com/torch2424/wasmBoy/blob/master/core/memory/dma.ts#L29).

ํ•˜์ง€๋งŒ @MaxGraey ๋˜๋Š” @dcodeIO ๊ฐ€ AS ๋˜๋Š” Wasm ๋žœ๋“œ ๋‚ด๋ถ€์—์„œ ๊ฐ€์žฅ ํšจ์œจ์ ์œผ๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๐Ÿ˜„ ๋น„๋ก ์ด๊ฒƒ์„ AS repo๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์ด ๋” ๋‚˜์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ

@fmkang ๋‹น์‹ ์€ ๋‹จ์ˆœํžˆ

export function allocateF32Array(length: i32): Float32Array {
  return new Float32Array(length);
}

AS ์ธก๊ณผ

let myArray = module.getArray(Float32Array, module.allocateF32Array(length));

JS ์ธก ์—์„œ loader ๋ฅผ ์‚ฌ์šฉ

@torch2424 ์˜ˆ, @binji ์˜ ์ฝ”๋“œ๋Š” JS ์ชฝ์— ์žˆ์ง€๋งŒ let myWasmArrayPtr = instance.exports.allocateF32Array(length) ๋Š” Wasm ๋ชจ๋“ˆ์—์„œ allocateF32Array ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(AssembleScript๋กœ ์ปดํŒŒ์ผ๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ). ์ด ๊ธฐ๋Šฅ์€ ๊ทธ์˜ ์Šค๋‹ˆํŽซ์ด๋‚˜ AS ๋‚ด์žฅ ๊ธฐ๋Šฅ์˜ ์ผ๋ถ€์— ์–ธ๊ธ‰๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฏ€๋กœ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‘ํ•˜๋Š” Wasm ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ด ํฌ์ธํ„ฐ๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์„ ๋ฌป๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@dcodeIO ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ „๋‹ฌ ๋ฐฐ์—ด์„ ๋‹จ์ˆœํ™”ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ์ƒˆ๋กœ์šด ์˜๊ฒฌ์„ ๊ฒŒ์‹œํ•˜๊ธฐ ์ „์— ์‹ ์ค‘ํ•˜๊ฒŒ ์‹คํ—˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด ๊ธฐ๋Šฅ์„ ๊ท€ํ•˜์˜ ๊ธฐ๋Šฅ์œผ๋กœ ๊ต์ฒดํ•œ ํ›„ ๋กœ๋“œ๋  ๋•Œ ๋‚ด ๋ชจ๋“ˆ์ด ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค. ์ฝ˜์†”์€ ๋งํ•œ๋‹ค

astest.html:1 Uncaught (in promise) TypeError: WebAssembly Instantiation: Import #0 module="env" error: module is not an object or function

๋‚ด AS ์ฝ”๋“œ์˜ ์•„๋ฌด ๊ณณ์—๋‚˜ let a = new Float32Array(10); ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์“ฐ๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@dcodeIO ( let c: f64[] = [a[0] + b[0], a[1] + b[1]]; ์™€ ๊ฐ™์€ ๋ฆฌํ„ฐ๋Ÿด ๋Œ€์‹ ) ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์—ด์˜ ์š”์†Œ์— ๊ฐ’์„ ํ• ๋‹นํ•˜๋ ค๊ณ  ํ•  ๋•Œ(์˜ˆ: let a: f64[] = [0, 0, 0]; a[0] = 1; ๋˜๋Š” let array = new Array<i32>(); array.push(1); ) Wasm ๋ชจ๋“ˆ์ด ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค

์ฒ˜์Œ์—๋Š” memory ๋ฅผ env ๋„ฃ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

var importObject = {
    env: { memory: new WebAssembly.Memory({initial:10}) },
    imports: { imported_func: arg => console.log(arg) }
};
WebAssembly.instantiate(wasmBinary, importObject).then(...);

๊ทธ๋Ÿฌ๋‚˜ ๋ฌธ์ œ๋Š” ์—ฌ์ „ํžˆ ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๊ฐ€ abort ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

env: {
    abort(msg, file, line, column) {
        console.error("abort called at main.ts:" + line + ":" + column);
    }
}

๋˜๋Š” ๋‹จ์ˆœํžˆ env: { abort: function(){} } ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์—†์œผ๋ฉฐ ์ฝ”๋“œ ์‹คํ–‰์ด ์‹ค์ œ๋กœ "์ค‘๋‹จ"๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ์ด ๋ฌธ์ œ์˜ ์‹ค์ œ ์›์ธ์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” WebAssembly๋ฅผ ์ฒ˜์Œ ์ ‘ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹จ์ง€ ์—…๋ฐ์ดํŠธ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด์ด ๊ฒŒ์‹œ๋ฌผ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹ต์žฅ์„ ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.

@fmkang ๋ชจ๋“ˆ์„ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๊ธฐ ์œ„ํ•ด AssemblyScript ๋กœ๋” ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋กœ๋”๋Š” ์ด๋ฏธ ์ค‘๋‹จ ๊ธฐ๋Šฅ๊ณผ ๊ฐ™์€ ๋ชจ๋“ˆ ๋‚ด๋ณด๋‚ด๊ธฐ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. AssemblyScript์— ๋Œ€ํ•ด ๋” ๊ถ๊ธˆํ•œ ์‚ฌํ•ญ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ ์ถ”์ ๊ธฐ ์— ๋ฌธ์˜ํ•ด ์ฃผ์‹œ๋ฉด ๊ธฐ๊บผ์ด ๋„์™€๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. :)

๊ทธ๋ž˜์„œ ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

let myArrayPtr = instance.exports.allocateF32Array(length);
let myArray = new Float32Array(instance.exports.memory.buffer, myArrayPtr, length);

// Use myArray as a normal Float32Array in JavaScript, fill in data, etc.
...

// Process the data in the array.
instance.exports.processF32Array(myArrayPtr, length);

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด processF32Array ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๋Š” RuntimeError: memory access out of bounds ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋กœ๋”, FWIW๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋˜ํ•œ ์‹œ๋„ํ–ˆ๋‹ค :

let myArray = module.getArray(Float32Array, module.allocateF32Array(length));

๊ทธ๋Ÿฌ๋‚˜ ๋‚ด ๋ชจ๋“ˆ์—๋Š” "getArray"๊ฐ€ ์—†์œผ๋ฉฐ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

WebAssembly๋กœ/์—์„œ ๋ฐฐ์—ด์„ ๋ณต์‚ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ฒฝ์šฐ AssemblyScript ๋ฐ @torch2424 ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ as-bind ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์„ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์–ด์…ˆ๋ธ”๋ฆฌ์Šคํฌ๋ฆฝํŠธ

export function sum(arr: Float64Array): f64 {
  let sum: f64 = 0;
  for(let i = 0; i < arr.length; i++) {
    sum += arr[i];
  }
  return sum;
}

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ(๋…ธ๋“œ)

const { AsBind } = require("as-bind");
const fs = require("fs");
const wasm = fs.readFileSync(__dirname + "/build/optimized.wasm");

const asyncTask = async () => {
  const asb = await AsBind.instantiate(wasm);

  // Make a large array
  console.time('Making array');
  let arr = new Float64Array(1e8).fill(1);
  console.timeEnd('Making array');

  // Find the sum using reduce
  console.time('Reduce');
  let sum1 = arr.reduce((acc, val) => acc + val, 0);
  console.timeEnd('Reduce');

  // Find the sum with for loops
  console.time('JS For');
  let sum2 = 0;
  for(let i = 0; i < arr.length; i++) sum2 += arr[i];
  console.timeEnd('JS For');

  // Find the sum with WebAssembly
  console.time('Wasm For');
  let sum3 = asb.exports.sum(arr);
  console.timeEnd('Wasm For');

  console.log(sum1, sum2, sum3);
};

asyncTask();

๋‚ด ์ปดํ“จํ„ฐ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

Making array: 789.086ms
Reduce: 2452.922ms
JS For: 184.818ms
Wasm For: 2008.482ms
100000000 100000000 100000000

์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์„ WebAssembly๋กœ ๋ณต์‚ฌํ•  ๋•Œ ์ƒ๋‹นํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ํ•ฉ๊ณ„๋ณด๋‹ค ๋” ๋น„์‹ผ ์ž‘์—…์— ๋Œ€ํ•ด ์ ˆ์ถฉ์ด ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘ํ•˜๋‹ค:

๋ฐฐ์—ด ๋ณต์‚ฌ๋ณธ์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด AssemblyScript์—์„œ ํ•ฉ๊ณ„๋ฅผ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค.

export function sum(arr: Float64Array): f64 {
  let sum: f64 = 0;
  return sum;
}

๊ทธ๋ฆฌ๊ณ  ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

Wasm ํ•ฉ๊ณ„ ์—†์Œ

Making array: 599.826ms
Reduce: 2810.395ms
JS For: 188.623ms
Wasm For: 762.481ms
100000000 100000000 0

๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ ์ž์ฒด๊ฐ€ 1์–ต f64 s ์ด์ƒ์„ ๋ณต์‚ฌํ•˜๋Š” ๋ฐ 762.481ms๊ฐ€ ๊ฑธ๋ฆฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@pwstegman ๋ฌด์ž‘์œ„ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  js ์—”์ง„์ด ๋ฃจํ”„๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. https://webassembly.studio/?f=5ux4ymi345e

Chrome ๋ฐ FF์˜ ๊ฒฝ์šฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

Chrome 81.0.4044.129

js sum: 129.968017578125ms
sum result = 49996811.62100115

js reduce: 1436.532958984375ms
js reduce result = 49996811.62100115

wasm sum: 153.000244140625ms
wasm sum result = 49996811.62100115

wasm reduce: 125.009033203125ms
wasm reduce result = 49996811.62100115

wasm empty: 0.002685546875ms

์•ˆ๋…•ํ•˜์„ธ์š”.
์ €๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ WASM์— ๋Œ€ํ•œ ์นœ์ˆ™ํ•จ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์‹ ์ƒ์•„์ด๋ฉฐ ์—ฌ๊ธฐ์™€ #1162์— ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. (์ด๊ฒƒ์ด ๋” ์ตœ๊ทผ ํ™œ๋™์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ์—ฌ๊ธฐ์— #1162 ๋Œ€๋ฅผ ๋ฌป๋Š”๋‹ค.)
๊ฐ„๋‹จํ•œ ์—ฐ๊ตฌ ํ›„ ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์•Œ์•„ ๋‚ด๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉด์„œ ๋ฐ๋ชจ ๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ  ๋ฐ์ดํ„ฐ ๋ณต์‚ฌ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์œ ํ˜•์ด ์ง€์ •๋œ ๋ฐฐ์—ด๋กœ WASM ๋ฉ”๋ชจ๋ฆฌ์— ๋ทฐ๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ JS ๊ด€์ ์—์„œ ์š”์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. :

// need to know the size in advance, that's OK since the impl makes some init 
const fft = new Module.KissFftReal(/*size=*/N);depending on the size anyway

// get view into WASM memory as Float64Array (of size=N in this case)
const input = fft.getInputTimeDataBuffer();

// fill 'input' buffer

// perform transformation, view into WASM memory is returned here (of size=(N + 2) in this case, +2 for Nyquist bin)
const output = fft.transform();

// use transformation result returned in 'output' buffer

์ด๊ฒƒ์ด ๊ฐˆ ๊ธธ์ธ๊ฐ€? ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ์ฃผ์ œ์— ๋Œ€ํ•œ ๋ชจ๋“  ์˜๊ฒฌ/์ƒˆ๋กœ ๊ณ ์นจ์„ ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ถ”์‹  ๋น„๋ก ์ถ”์•…ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์‹ค์ œ๋กœ ๋‚˜๋ฅผ ์œ„ํ•ด ํ™˜์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค (๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ์ดํ•ดํ•˜๊ณ  ๊ฐ์‚ฌํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ)

pps
๋‹ค์Œ์€ ์œ ์‚ฌํ•œ ๋ฌธ์ œ์— ๊ด€ํ•œ ๋‚ด (์•„์ง ๋‹ต๋ณ€๋˜์ง€ ์•Š์€) stackoverflow ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

https://stackoverflow.com/questions/65566923/is-there-a-more-efficient-way-to-return-arrays-from-c-to-javascript

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰

๊ด€๋ จ ๋ฌธ์ œ

konsoletyper picture konsoletyper  ยท  6์ฝ”๋ฉ˜ํŠธ

JimmyVV picture JimmyVV  ยท  4์ฝ”๋ฉ˜ํŠธ

dpw picture dpw  ยท  3์ฝ”๋ฉ˜ํŠธ

Artur-A picture Artur-A  ยท  3์ฝ”๋ฉ˜ํŠธ

aaabbbcccddd00001111 picture aaabbbcccddd00001111  ยท  3์ฝ”๋ฉ˜ํŠธ