git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 0c79dfe47f09117aac1561665a4c2933c4cc17d7

Merge pull request #6 from ewasm/proper-wasm-export

Export methods to WASM properly
wanderer authored on 8/3/2016, 6:45:23 PM
GitHub committed on 8/3/2016, 6:45:23 PM
Parent: c137aba03aa9981099698af3a30df2969c42a73b
Parent: 184bf886b55ace71c3b15786ecd494c3973ca8d6

Files changed

index.jschanged
interface.jschanged
index.jsView
@@ -26,9 +26,9 @@
2626
2727 // handles running code.
2828 static codeHandler (code, ethInterface = new Interface(new Environment())) {
2929 const instance = Wasm.instantiateModule(code, {
30- 'ethereum': ethInterface
30+ 'ethereum': ethInterface.exportTable
3131 })
3232
3333 ethInterface.setModule(instance)
3434 if (instance.exports.main) {
interface.jsView
@@ -2,63 +2,98 @@
22 * This is the Ethereum interface that is exposed to the WASM instance which
33 * enables to interact with the Ethereum Environment
44 */
55 const constants = require('./constants.js')
6-// const Graph = require('generic-digraph')
7-// function.bind is not working corretly whith Wasm imports. So instead create
8-// a global for now. TODO REMOVE
9-let ENV
10-let MOD
6+
117 // The interface exposed to the WebAessembly Core
128 module.exports = class Interface {
139 print (a) {
1410 console.log(a)
1511 }
1612
1713 memPrint () {
18- console.log((new Uint8Array(MOD.exports.memory)).toString())
14+ console.log((new Uint8Array(this.module.exports.memory)).toString())
1915 }
2016
2117 constructor (environment) {
22- ENV = this.environment = environment
18+ this.environment = environment
2319 }
2420
21+ get exportTable () {
22+ let exportMethods = [
23+ // include all the public methods according to the Ethereum Environment Interface (EEI)
24+ // FIXME: this currently doesn't match EEI r0
25+ 'useGas',
26+ 'gas',
27+ 'address',
28+ 'balance',
29+ 'origin',
30+ 'caller',
31+ 'callValue',
32+ 'callDataSize',
33+ 'callDataCopy',
34+ 'codeSize',
35+ 'codeCopy',
36+ 'extCodeSize',
37+ 'extCodeCopy',
38+ 'gasPrice',
39+ 'blockHash',
40+ 'coinbase',
41+ 'timestamp',
42+ 'number',
43+ 'difficulty',
44+ 'gasLimit',
45+ 'log',
46+ 'create',
47+ 'call',
48+ 'callDelegate',
49+ 'sstore',
50+ 'sload',
51+ 'return',
52+ 'suicide'
53+ ]
54+ let ret = {}
55+ exportMethods.forEach((method) => {
56+ ret[method] = this[method].bind(this)
57+ })
58+ return ret
59+ }
2560
2661 // FIXME: this shouldn't be needed
2762 get env () {
28- return ENV
63+ return this.environment
2964 }
3065
3166 setModule (mod) {
32- this.module = MOD = mod
67+ this.module = mod
3368 }
3469
3570 /**
3671 * Subtracts an amount to the gas counter
3772 * @param {integer} amount the amount to subtract to the gas counter
3873 */
3974 useGas (amount) {
4075 if (amount > 0) {
41- ENV.gasLimit -= amount
76+ this.environment.gasLimit -= amount
4277 }
4378 }
4479
4580 /**
4681 * Returns the current amount of gas
4782 * @return {integer}
4883 */
4984 gas () {
50- return ENV.gasLimit
85+ return this.environment.gasLimit
5186 }
5287
5388 /**
5489 * Gets address of currently executing account and loads it into memory at
5590 * the given offset.
5691 * @param {integer} offset
5792 */
5893 address (offset) {
59- const address = ENV.address
60- const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
94+ const address = this.environment.address
95+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.ADD_SIZE_BYTES)
6196 memory.set(address)
6297 }
6398
6499 /**
@@ -67,12 +102,12 @@
67102 * @param {integer} addressOffset the memory offset to laod the address
68103 * @param {integer} resultOffset
69104 */
70105 balance (addressOffset, offset) {
71- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
72- const memory = new Uint8Array(MOD.exports.memory, offset, constants.MAX_BAL_BYTES)
106+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
107+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.MAX_BAL_BYTES)
73108 // call the parent contract and ask for the balance of one of its child contracts
74- const balance = ENV.parent.environment.getBalance(address)
109+ const balance = this.environment.parent.environment.getBalance(address)
75110 memory.set(balance)
76111 }
77112
78113 /**
@@ -81,10 +116,10 @@
81116 * account with non-empty associated code.
82117 * @param {integer} offset
83118 */
84119 origin (offset) {
85- const origin = ENV.origin
86- const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
120+ const origin = this.environment.origin
121+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.ADD_SIZE_BYTES)
87122 memory.set(origin)
88123 }
89124
90125 /**
@@ -92,10 +127,10 @@
92127 * the address of the account that is directly responsible for this execution.
93128 * @param {integer} offset
94129 */
95130 caller (offset) {
96- const caller = ENV.caller
97- const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
131+ const caller = this.environment.caller
132+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.ADD_SIZE_BYTES)
98133 memory.set(caller)
99134 }
100135
101136 /**
@@ -103,10 +138,10 @@
103138 * this execution and loads it into memory at the given location.
104139 * @param {integer} offset
105140 */
106141 callValue (offset) {
107- const callValue = ENV.callValue
108- const memory = new Uint8Array(MOD.exports.memory, offset, constants.MAX_BAL_BYTES)
142+ const callValue = this.environment.callValue
143+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.MAX_BAL_BYTES)
109144 memory.set(callValue)
110145 }
111146
112147 /**
@@ -114,9 +149,9 @@
114149 * data passed with the message call instruction or transaction.
115150 * @return {integer}
116151 */
117152 callDataSize () {
118- return ENV.callData.byteLength
153+ return this.environment.callData.byteLength
119154 }
120155
121156 /**
122157 * Copys the input data in current environment to memory. This pertains to
@@ -125,19 +160,19 @@
125160 * @param {integer} dataOffset the offset in the input data
126161 * @param {integer} length the length of data to copy
127162 */
128163 callDataCopy (offset, dataOffset, length) {
129- const callData = new Uint8Array(ENV.callData, offset, length)
130- const memory = new Uint8Array(MOD.exports.memory, offset, length)
164+ const callData = new Uint8Array(this.environment.callData, offset, length)
165+ const memory = new Uint8Array(this.module.exports.memory, offset, length)
131166 memory.set(callData)
132167 }
133168
134169 /**
135170 * Gets the size of code running in current environment.
136171 * @return {interger}
137172 */
138173 codeSize () {
139- return ENV.code.byteLength
174+ return this.environment.code.byteLength
140175 }
141176
142177 /**
143178 * Copys the code running in current environment to memory.
@@ -145,10 +180,10 @@
145180 * @param {integer} codeOffset the code offset
146181 * @param {integer} length the length of code to copy
147182 */
148183 codeCopy (offset, codeOffset, length) {
149- const code = new Uint8Array(ENV.code, codeOffset, length)
150- const memory = new Uint8Array(MOD.exports.memory, offset, length)
184+ const code = new Uint8Array(this.environment.code, codeOffset, length)
185+ const memory = new Uint8Array(this.module.exports.memory, offset, length)
151186 memory.set(code)
152187 }
153188
154189 /**
@@ -156,9 +191,9 @@
156191 * @param {integer} addressOffset the offset in memory to load the address from
157192 * @return {integer}
158193 */
159194 extCodeSize (addressOffset) {
160- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
195+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
161196 const code = this.environment.getCode(address)
162197 return code.byteLength
163198 }
164199
@@ -169,21 +204,21 @@
169204 * @param {integer} codeOffset the code offset
170205 * @param {integer} length the length of code to copy
171206 */
172207 extCodeCopy (addressOffset, offset, codeOffset, length) {
173- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
208+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
174209 let code = this.environment.getCode(address)
175210 code = new Uint8Array(code, codeOffset, length)
176- const memory = new Uint8Array(MOD.exports.memory, offset, length)
211+ const memory = new Uint8Array(this.module.exports.memory, offset, length)
177212 memory.set(code)
178213 }
179214
180215 /**
181216 * Gets price of gas in current environment.
182217 * @return {integer}
183218 */
184219 gasPrice () {
185- return ENV.gasPrice
220+ return this.environment.gasPrice
186221 }
187222
188223 /**
189224 * Gets the hash of one of the 256 most recent complete blocks.
@@ -191,51 +226,51 @@
191226 * @param {integer} offset the offset to load the hash into
192227 */
193228 blockHash (number, offset) {
194229 const hash = this.environment.getBlockHash(number)
195- const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
230+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.ADD_SIZE_BYTES)
196231 memory.set(hash)
197232 }
198233
199234 /**
200235 * Gets the block’s beneficiary address and loads into memory.
201236 * @param offset
202237 */
203238 coinbase (offset) {
204- const memory = new Uint8Array(MOD.exports.memory, offset, constants.ADD_SIZE_BYTES)
205- memory.set(ENV.coinbase)
239+ const memory = new Uint8Array(this.module.exports.memory, offset, constants.ADD_SIZE_BYTES)
240+ memory.set(this.environment.coinbase)
206241 }
207242
208243 /**
209244 * Get the block’s timestamp.
210245 * @return {integer}
211246 */
212247 timestamp () {
213- return ENV.timestamp
248+ return this.environment.timestamp
214249 }
215250
216251 /**
217252 * Get the block’s number.
218253 * @return {integer}
219254 */
220255 number () {
221- return ENV.number
256+ return this.environment.number
222257 }
223258
224259 /**
225260 * Get the block’s difficulty.
226261 * @return {integer}
227262 */
228263 difficulty () {
229- return ENV.difficulty
264+ return this.environment.difficulty
230265 }
231266
232267 /**
233268 * Get the block’s gas limit.
234269 * @return {integer}
235270 */
236271 gasLimit () {
237- return ENV.gasLimit
272+ return this.environment.gasLimit
238273 }
239274
240275 /**
241276 * Creates a new log in the current environment
@@ -243,10 +278,10 @@
243278 * @param {integer} length the data length
244279 * TODO: replace with variadic
245280 */
246281 log (dataOffset, length, topic1, topic2, topic3, topic4, topic5) {
247- const data = new Uint8Array(MOD.exports.memory, dataOffset, length)
248- ENV.logs.push({
282+ const data = new Uint8Array(this.module.exports.memory, dataOffset, length)
283+ this.environment.logs.push({
249284 data: data,
250285 topics: [topic1, topic2, topic3, topic4, topic5]
251286 })
252287 }
@@ -257,11 +292,11 @@
257292 * @param {integer} dataOffset the offset to load the code for the new contract from
258293 * @param {integer} length the data length
259294 */
260295 create (valueOffset, dataOffset, length) {
261- const value = new Uint8Array(MOD.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
262- const data = new Uint8Array(MOD.exports.memory, dataOffset, length)
263- const result = ENV.create(value, data)
296+ const value = new Uint8Array(this.module.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
297+ const data = new Uint8Array(this.module.exports.memory, dataOffset, length)
298+ const result = this.environment.create(value, data)
264299 return result
265300 }
266301
267302 /**
@@ -280,14 +315,14 @@
280315 if (gas === undefined) {
281316 gas = this.gasLeft()
282317 }
283318 // Load the params from mem
284- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
285- const value = new Uint8Array(MOD.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
286- const data = new Uint8Array(MOD.exports.memory, dataOffset, dataLength)
319+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
320+ const value = new Uint8Array(this.module.exports.memory, valueOffset, constants.MAX_BAL_BYTES)
321+ const data = new Uint8Array(this.module.exports.memory, dataOffset, dataLength)
287322 // Run the call
288- const [result, errorCode] = ENV.call(gas, address, value, data)
289- const memory = new Uint8Array(MOD.exports.memory, resultOffset, resultLength)
323+ const [result, errorCode] = this.environment.call(gas, address, value, data)
324+ const memory = new Uint8Array(this.module.exports.memory, resultOffset, resultLength)
290325 memory.set(result)
291326
292327 return errorCode
293328 }
@@ -304,12 +339,12 @@
304339 * @param {integer} resultLength
305340 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
306341 */
307342 callDelegate (gas, addressOffset, dataOffset, dataLength, resultOffset, resultLength) {
308- const data = new Uint8Array(MOD.exports.memory, dataOffset, dataLength)
309- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
343+ const data = new Uint8Array(this.module.exports.memory, dataOffset, dataLength)
344+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
310345 const [result, errorCode] = this.environment.callDelegate(gas, address, data)
311- const memory = new Uint8Array(MOD.exports.memory, resultOffset, resultLength)
346+ const memory = new Uint8Array(this.module.exports.memory, resultOffset, resultLength)
312347 memory.set(result)
313348
314349 return errorCode
315350 }
@@ -320,24 +355,24 @@
320355 * @param {interger} pathOffest the memory offset to load the the path from
321356 * @param {interger} valueOffset the memory offset to load the value from
322357 */
323358 sstore (pathOffest, valueOffset) {
324- const path = new Buffer(MOD.exports.memory, pathOffest, 32).toString('hex')
325- const value = new Uint8Array(MOD.exports.memory, valueOffset, 32)
326- const oldValue = ENV.state.get(path)
359+ const path = new Buffer(this.module.exports.memory, pathOffest, 32).toString('hex')
360+ const value = new Uint8Array(this.module.exports.memory, valueOffset, 32)
361+ const oldValue = this.environment.state.get(path)
327362 const valIsZero = value.every((i) => i === 0)
328363
329364 // write
330365 if (!valIsZero && !oldValue) {
331- ENV.gasLimit -= 15000
366+ this.environment.gasLimit -= 15000
332367 }
333368
334369 // delete
335370 if (valIsZero && oldValue) {
336- ENV.gasRefund += 15000
337- ENV.state.delete(path)
371+ this.environment.gasRefund += 15000
372+ this.environment.state.delete(path)
338373 } else {
339- ENV.state.set(path, value)
374+ this.environment.state.set(path, value)
340375 }
341376 }
342377
343378 /**
@@ -345,11 +380,11 @@
345380 * @param {interger} pathOffest the memory offset to load the the path from
346381 * @param {interger} resultOffset the memory offset to load the value from
347382 */
348383 sload (pathOffest, resultOffset) {
349- const path = new Buffer(MOD.exports.memory, pathOffest, 32).toString('hex')
350- const result = ENV.state.get(path)
351- const memory = new Uint8Array(MOD.exports.memory, resultOffset, 32)
384+ const path = new Buffer(this.module.exports.memory, pathOffest, 32).toString('hex')
385+ const result = this.environment.state.get(path)
386+ const memory = new Uint8Array(this.module.exports.memory, resultOffset, 32)
352387 memory.set(result)
353388 }
354389
355390 /**
@@ -357,17 +392,47 @@
357392 * @param {integer} offset the offset of the output data.
358393 * @param {integer} length the length of the output data.
359394 */
360395 return (offset, length) {
361- ENV.returnValue = new Uint8Array(MOD.exports.memory, offset, length)
396+ this.environment.returnValue = new Uint8Array(this.module.exports.memory, offset, length)
362397 }
363398
364399 /**
365400 * Halt execution and register account for later deletion giving the remaining
366401 * balance to an address path
367402 * @param {integer} offset the offset to load the address from
368403 */
369404 suicide (addressOffset) {
370- const address = new Uint8Array(MOD.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
405+ const address = new Uint8Array(this.module.exports.memory, addressOffset, constants.ADD_SIZE_BYTES)
371406 this.environment.suicideAddress = address
372407 }
373408 }
409+
410+//
411+// Polyfill required unless this is sorted: https://bugs.chromium.org/p/chromium/issues/detail?id=633895
412+//
413+// Polyfill from: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
414+//
415+Function.prototype.bind = function (oThis) { // eslint-disable-line
416+ if (typeof this !== 'function') {
417+ // closest thing possible to the ECMAScript 5
418+ // internal IsCallable function
419+ throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
420+ }
421+
422+ var aArgs = Array.prototype.slice.call(arguments, 1)
423+ var fToBind = this
424+ var fNOP = function () {}
425+ var fBound = function () {
426+ return fToBind.apply(this instanceof fNOP ? this : oThis,
427+ aArgs.concat(Array.prototype.slice.call(arguments)))
428+ }
429+
430+ if (this.prototype) {
431+ // Function.prototype doesn't have a prototype property
432+ fNOP.prototype = this.prototype
433+ }
434+
435+ fBound.prototype = new fNOP() // eslint-disable-line new-cap
436+
437+ return fBound
438+}

Built with git-ssb-web