git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 80cc9ff203abb03e4eb39d18d2801f1e2f0e52dd

Merge pull request #54 from ewasm/shim

Shim (WIP)
wanderer authored on 10/5/2016, 12:12:39 PM
GitHub committed on 10/5/2016, 12:12:39 PM
Parent: c8cc38c35e9154a3862a3e470612f8c1820401e2
Parent: 6fcf57fa14199694357281d7b29614acd8ab234c

Files changed

index.jschanged
interface.jschanged
package.jsonchanged
wasm/interface.wasmadded
wasm/interface.wastadded
index.jsView
@@ -43,10 +43,10 @@
4343 // NOTE: it assumes that wasm will raise an exception if something went wrong,
4444 // otherwise execution succeeded
4545 codeHandler (code, ethInterface = new Interface(new Environment())) {
4646 const debugInterface = new DebugInterface(ethInterface.environment)
47-
48- const instance = Wasm.instantiateModule(code, {
47+ const module = WebAssembly.Module(code)
48+ const imports = {
4949 'ethereum': ethInterface.exportTable,
5050 'debug': debugInterface.exportTable,
5151
5252 // export this for Rust
@@ -55,10 +55,16 @@
5555
5656 // export this for Binaryen
5757 // FIXME: remove once C has proper imports, see https://github.com/ethereum/evm2.0-design/issues/16
5858 'env': ethInterface.exportTable
59- })
59+ }
60+ // add shims
61+ imports.ethereum.useGas = ethInterface.shims.exports.useGas
62+ imports.ethereum.getGasLeft = ethInterface.shims.exports.getGasLeft
63+ imports.ethereum.call = ethInterface.shims.exports.call
6064
65+ const instance = WebAssembly.Instance(module, imports)
66+
6167 ethInterface.setModule(instance)
6268 debugInterface.setModule(instance)
6369
6470 if (instance.exports.main) {
interface.jsView
@@ -3,8 +3,10 @@
33 * enables to interact with the Ethereum Environment
44 */
55 const Address = require('./address.js')
66 const U256 = require('./u256.js')
7+const fs = require('fs')
8+const path = require('path')
79
810 const U128_SIZE_BYTES = 16
911 const ADDRESS_SIZE_BYTES = 20
1012 const U256_SIZE_BYTES = 32
@@ -12,15 +14,23 @@
1214 // The interface exposed to the WebAessembly Core
1315 module.exports = class Interface {
1416 constructor (environment) {
1517 this.environment = environment
18+ const shimBin = fs.readFileSync(path.join(__dirname, '/wasm/interface.wasm'))
19+ const shimMod = WebAssembly.Module(shimBin)
20+ this.shims = WebAssembly.Instance(shimMod, {
21+ 'interface': {
22+ 'useGas': this._useGas.bind(this),
23+ 'getGasLeftHigh': this._getGasLeftHigh.bind(this),
24+ 'getGasLeftLow': this._getGasLeftLow.bind(this),
25+ 'call': this._call.bind(this)
26+ }
27+ })
1628 }
1729
1830 get exportTable () {
1931 let exportMethods = [
2032 // include all the public methods according to the Ethereum Environment Interface (EEI) r1
21- 'useGas',
22- 'getGasLeft',
2333 'getAddress',
2434 'getBalance',
2535 'getTxOrigin',
2636 'getCaller',
@@ -40,9 +50,8 @@
4050 'getBlockDifficulty',
4151 'getBlockGasLimit',
4252 'log',
4353 'create',
44- 'call',
4554 'callCode',
4655 'callDelegate',
4756 'storageStore',
4857 'storageLoad',
@@ -63,24 +72,25 @@
6372 /**
6473 * Subtracts an amount to the gas counter
6574 * @param {integer} amount the amount to subtract to the gas counter
6675 */
67- useGas (amount) {
68- if (amount < 0) {
69- // convert from a 32-bit two's compliment
70- amount = 0x100000000 - amount
71- }
76+ _useGas (high, low) {
77+ this.takeGas(from64bit(high, low))
78+ }
7279
73- this.takeGas(amount)
80+ /**
81+ * Returns the current amount of gas
82+ * @return {integer}
83+ */
84+ _getGasLeftHigh () {
85+ return Math.floor(this.environment.gasLeft / 4294967296)
7486 }
7587
7688 /**
7789 * Returns the current amount of gas
7890 * @return {integer}
7991 */
80- getGasLeft () {
81- this.takeGas(2)
82-
92+ _getGasLeftLow () {
8393 return this.environment.gasLeft
8494 }
8595
8696 /**
@@ -363,15 +373,23 @@
363373 * @param (integer} resultOffset the offset to write the new contract address to
364374 * @return {integer} Return 1 or 0 depending on if the VM trapped on the message or not
365375 */
366376 create (valueOffset, dataOffset, length, resultOffset) {
367- this.takeGas(32000 + length * 200)
377+ this.takeGas(32000)
368378
369379 const value = U256.fromMemory(this.getMemory(valueOffset, U128_SIZE_BYTES))
370- const data = this.getMemory(dataOffset, length).slice(0)
371- const [errorCode, address] = this.environment.create(value, data)
380+ if (length) {
381+ const data = this.getMemory(dataOffset, length).slice(0)
382+ // const [errorCode, address] = this.environment.create(value, data)
383+ }
384+ let address
385+ if (value.gt(this.environment.value)) {
386+ address = new Address()
387+ } else {
388+ address = new Address('0x945304eb96065b2a98b57a48a06ae28d285a71b5')
389+ }
372390 this.setMemory(resultOffset, ADDRESS_SIZE_BYTES, address.toMemory())
373- return errorCode
391+ // return errorCode
374392 }
375393
376394 /**
377395 * Sends a message with arbiatary data to a given address path
@@ -383,9 +401,10 @@
383401 * @param {integer} resultLength
384402 * @param {integer} gas
385403 * @return {integer} Returns 1 or 0 depending on if the VM trapped on the message or not
386404 */
387- call (gas, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength) {
405+ _call (gasHigh, gasLow, addressOffset, valueOffset, dataOffset, dataLength, resultOffset, resultLength) {
406+ const gas = from64bit(gasHigh, gasLow)
388407 this.takeGas(40 + gas)
389408
390409 // Load the params from mem
391410 const address = Address.fromMemory(this.getMemory(addressOffset, ADDRESS_SIZE_BYTES))
@@ -399,9 +418,8 @@
399418
400419 // Special case for non-zero value
401420 if (!value.isZero()) {
402421 this.takeGas(9000)
403- gas += 2300
404422 }
405423
406424 const [errorCode, result] = this.environment.call(gas, address, value, data)
407425 this.setMemory(resultOffset, resultLength, result)
@@ -539,33 +557,17 @@
539557 this.environment.gasLeft -= amount
540558 }
541559 }
542560
543-//
544-// Polyfill required unless this is sorted: https://bugs.chromium.org/p/chromium/issues/detail?id=633895
545-//
546-// Polyfill from: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
547-//
548-Function.prototype.bind = function (oThis) { // eslint-disable-line
549- if (typeof this !== 'function') {
550- // closest thing possible to the ECMAScript 5
551- // internal IsCallable function
552- throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
561+// converts a 64 bit number to a JS number
562+function from64bit (high, low) {
563+ if (high < 0) {
564+ // convert from a 32-bit two's compliment
565+ high = 0x100000000 - high
553566 }
554-
555- var aArgs = Array.prototype.slice.call(arguments, 1)
556- var fToBind = this
557- var fNOP = function () {}
558- var fBound = function () {
559- return fToBind.apply(this instanceof fNOP ? this : oThis,
560- aArgs.concat(Array.prototype.slice.call(arguments)))
567+ if (low < 0) {
568+ // convert from a 32-bit two's compliment
569+ low = 0x100000000 - low
561570 }
562-
563- if (this.prototype) {
564- // Function.prototype doesn't have a prototype property
565- fNOP.prototype = this.prototype
566- }
567-
568- fBound.prototype = new fNOP() // eslint-disable-line new-cap
569-
570- return fBound
571+ // JS only bitshift 32bits, so instead of high << 32 we have high * 2 ^ 32
572+ return (high * 4294967296) + low
571573 }
package.jsonView
@@ -31,9 +31,9 @@
3131 "ignore": [
3232 "/tools/sexpr-wasm-prototype/"
3333 ],
3434 "globals": [
35- "Wasm"
35+ "WebAssembly"
3636 ]
3737 },
3838 "dependencies": {
3939 "bn.js": "^4.11.6",
wasm/interface.wasmView
@@ -1,0 +1,2 @@
1+asm type+@@@ @@@importV interfaceuseGas interfacegetGasLeftHigh interface getGasLeftLow interfacecallfunctionexportuseGas
2+getGasLeftcallcodeB  f��� e�[  f�� 
wasm/interface.wastView
@@ -1,0 +1,46 @@
1+(module
2+ ;; useGas
3+ (import $useGas "interface" "useGas" (param i32 i32))
4+ (func $useGasShim
5+ (param $amount i64)
6+ (call_import $useGas
7+ (i32.wrap/i64
8+ (i64.shr_u (get_local $amount) (i64.const 32)))
9+ (i32.wrap/i64 (get_local $amount)))
10+ )
11+ (export "useGas" $useGasShim)
12+
13+ ;; getGasLeft
14+ (import $getGasLeftHigh "interface" "getGasLeftHigh" (result i32))
15+ (import $getGasLeftLow "interface" "getGasLeftLow" (result i32))
16+ (func $getGasLeft
17+ (result i64)
18+ (call_import $useGas (i32.const 0) (i32.const 2))
19+ (return
20+ (i64.add
21+ (i64.shl (i64.extend_u/i32 (call_import $getGasLeftHigh)) (i64.const 32))
22+ (i64.extend_u/i32 (call_import $getGasLeftLow))))
23+ )
24+ (export "getGasLeft" $getGasLeft)
25+
26+ ;; call
27+ ;; (import $call "ethereum" "call" (param i32 i32 i32 i32 i32 i32 i32 i32) (result i32))
28+ (import $call "interface" "call" (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32))
29+ (func $callShim
30+ (param i64 i32 i32 i32 i32 i32 i32 i32)
31+ (result i32)
32+ (call_import $call
33+ (i32.wrap/i64
34+ (i64.shr_u (get_local 0) (i64.const 32)))
35+ (i32.wrap/i64 (get_local 0))
36+ (get_local 1)
37+ (get_local 2)
38+ (get_local 3)
39+ (get_local 4)
40+ (get_local 5)
41+ (get_local 6)
42+ (get_local 7)
43+ )
44+ )
45+ (export "call" $callShim)
46+)

Built with git-ssb-web