Skip to content

Commit

Permalink
fix(transform-metering): only enable meters; the host has to disable
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Feb 12, 2020
1 parent 53c4549 commit d1b8e84
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 30 deletions.
12 changes: 12 additions & 0 deletions packages/tame-metering/src/tame.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ export function tameMetering() {
// The wrapper needs construct behaviour.
isConstructor = true;
wrapper = function meteredConstructor(...args) {
if (!globalMeter) {
// Fast path.
const newTarget = new.target;
if (newTarget) {
return construct(target, args, newTarget);
}
return apply(target, this, args);
}
// We're careful not to use the replaceGlobalMeter function as
// it may consume some stack.
// Instead, directly manipulate the globalMeter variable.
Expand Down Expand Up @@ -116,6 +124,10 @@ export function tameMetering() {
const { name = '' } = target;
({ [name]: wrapper } = {
[name](...args) {
// Fast path:
if (!globalMeter) {
return apply(target, this, args);
}
// We're careful not to use the replaceGlobalMeter function as
// it may consume some stack.
// Instead, directly manipulate the globalMeter variable.
Expand Down
12 changes: 10 additions & 2 deletions packages/transform-metering/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { makeMeteredEvaluator } from '@agoric/transform-metering';
// Create a new SES instance (root realm).
const sesRealm = SES1.makeSESRootRealm({
shims: [SES1TameMeteringShim],
deoptimizeStableGlobals: true,
configurableGlobals: true,
});

const replaceGlobalMeter = SES1ReplaceGlobalMeter(sesRealm);
Expand All @@ -30,7 +30,15 @@ const meteredEval = makeMeteredEvaluator({
// Needed for source transforms that prevent runaways.
babelCore,
// Create an object with an `evaluate(src, endowments, options)` method
makeEvaluator: opts => sesRealm.global.Realm.makeCompartment(opts);
makeEvaluator: opts => {
const c = sesRealm.global.Realm.makeCompartment(opts);
// FIXME: Realms bug doesn't propagate global properties.
Object.defineProperties(
c.global,
Object.getOwnPropertyDescriptors(sesRealm.global),
);
return c;
},
// Call a callback when the code inside the meteredEval is done evaluating.
quiesceCallback: cb => setTimeout(cb),
});
Expand Down
8 changes: 6 additions & 2 deletions packages/transform-metering/src/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ export function makeMeteredEvaluator({

if (typeof srcOrThunk === 'string') {
// Transform the source on our own budget, then evaluate against the meter.
endowments.getGlobalMeter = m =>
m === true ? meter : replaceGlobalMeter(m);
endowments.getGlobalMeter = m => {
if (m !== true) {
replaceGlobalMeter(meter);
}
return meter;
};
returned = ev.evaluate(srcOrThunk, endowments);
} else {
// Evaluate the thunk with the specified meter.
Expand Down
12 changes: 2 additions & 10 deletions packages/transform-metering/src/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ const ${reid}=RegExp(${JSON.stringify(pattern)},${JSON.stringify(flags)});`);

// Meter by the regular expressions in use.
const regexpSource = regexpList.join('');
const preSource = `const ${getMeterId}=getGlobalMeter;const ${meterId}=${setMeterId}(true);\
const preSource = `const ${getMeterId}=getGlobalMeter;const ${meterId}=${getMeterId}();\
${meterId}&&${meterId}.${c.METER_ENTER}();\
try{${regexpSource}`;
const postSource = `\n}finally{${setMeterId}(false);${meterId} && ${meterId}.${c.METER_LEAVE}();}`;
const postSource = `\n}finally{${meterId} && ${meterId}.${c.METER_LEAVE}();}`;

// Force into an IIFE, if necessary.
const maybeSource = output.code;
Expand All @@ -212,14 +212,6 @@ try{${regexpSource}`;

// console.log('metered source:', `\n${actualSource}`);

// Install the specified user meter.
const savedMeter = endowments.getGlobalMeter();
endowments[setMeterId] = set => {
const m = set ? meter : savedMeter;
endowments.getGlobalMeter(m);
return m;
};

return {
...ss,
ast,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{() => {const $m = $h‍_meter_get();$m && $m.e();try {
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{() => {const $m = $h‍_meter_get();$m && $m.e();try {
f();} finally {$m && $m.l();}};
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{() => {const $m = $h‍_meter_get();$m && $m.e();try {return (
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{() => {const $m = $h‍_meter_get();$m && $m.e();try {return (
f());} finally {$m && $m.l();}};
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
4 changes: 2 additions & 2 deletions packages/transform-metering/testdata/classes/rewrite.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{class Abc {
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{class Abc {
f() {const $m = $h‍_meter_get();$m && $m.e();try {
return doit();
} finally {$m && $m.l();}}}
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{a = {
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{a = {
f() {const $m = $h‍_meter_get();$m && $m.e();try {
doit();
} finally {$m && $m.l();}} };
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
4 changes: 2 additions & 2 deletions packages/transform-metering/testdata/for-loops/rewrite.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{for (const f of b) {$m && $m.c();
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{for (const f of b) {$m && $m.c();
doit(f);}

for (const p in bar) {$m && $m.c();
doit(p);}

for (let i = 0; i < 3; i++) {$m && $m.c();
doit(i);}
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{(function () {const $m = $h‍_meter_get();$m && $m.e();try {
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{(function () {const $m = $h‍_meter_get();$m && $m.e();try {
f();
} finally {$m && $m.l();}});
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{const $re_0=RegExp("^my-favourite-regexp","");if ($re_0.test('myf')) {
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{const $re_0=RegExp("^my-favourite-regexp","");if ($re_0.test('myf')) {
doit();
}
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}
4 changes: 2 additions & 2 deletions packages/transform-metering/testdata/while-loops/rewrite.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_set(true);$m&&$m.e();try{while (a) {$m && $m.c();}
const $h‍_meter_get=getGlobalMeter;const $m=$h‍_meter_get();$m&&$m.e();try{while (a) {$m && $m.c();}

while (a) {$m && $m.c();doit();}

Expand All @@ -9,4 +9,4 @@ while (a) {$m && $m.c();
do {$m && $m.c();
doit();} while (
a);
}finally{$h‍_meter_set(false);$m && $m.l();}
}finally{$m && $m.l();}

0 comments on commit d1b8e84

Please sign in to comment.