@@ -12,19 +12,23 @@ const { get: wmGet, set: wmSet } = WeakMap.prototype;
12
12
13
13
const ObjectConstructor = Object ;
14
14
15
- let setGlobalMeter ;
15
+ let replaceGlobalMeter ;
16
16
17
17
export default function tameMetering ( ) {
18
- if ( setGlobalMeter ) {
18
+ if ( replaceGlobalMeter ) {
19
19
// Already installed.
20
- return setGlobalMeter ;
20
+ return replaceGlobalMeter ;
21
21
}
22
22
23
- let globalMeter ;
23
+ let globalMeter = null ;
24
24
const wrapped = new WeakMap ( ) ;
25
25
const setWrapped = ( ...args ) => apply ( wmSet , wrapped , args ) ;
26
26
const getWrapped = ( ...args ) => apply ( wmGet , wrapped , args ) ;
27
27
28
+ /*
29
+ setWrapped(Error, Error); // FIGME: debugging
30
+ setWrapped(console, console); // FIGME
31
+ */
28
32
const wrapDescriptor = desc => {
29
33
const newDesc = { } ;
30
34
for ( const [ k , v ] of entries ( desc ) ) {
@@ -34,16 +38,11 @@ export default function tameMetering() {
34
38
return newDesc ;
35
39
} ;
36
40
37
- function wrap ( target , deepMeter = globalMeter ) {
41
+ function wrap ( target ) {
38
42
if ( ObjectConstructor ( target ) !== target ) {
39
43
return target ;
40
44
}
41
45
42
- const meter = globalMeter ;
43
- if ( target === meter ) {
44
- return target ;
45
- }
46
-
47
46
let wrapper = getWrapped ( target ) ;
48
47
if ( wrapper ) {
49
48
return wrapper ;
@@ -52,33 +51,50 @@ export default function tameMetering() {
52
51
if ( typeof target === 'function' ) {
53
52
// Meter the call to the function/constructor.
54
53
wrapper = function meterFunction ( ...args ) {
55
- // We first install no meter to make metering explicit.
56
- const userMeter = setGlobalMeter ( null ) ;
54
+ // We're careful not to use the replaceGlobalMeter function as
55
+ // it may consume some stack.
56
+ // Instead, directly manipulate the globalMeter variable.
57
+ const savedMeter = globalMeter ;
57
58
try {
58
- userMeter && userMeter [ c . METER_ENTER ] ( ) ;
59
+ // This is a common idiom to disable global metering so
60
+ // that the savedMeter can use builtins without
61
+ // recursively calling itself.
62
+
63
+ // Track the entry of the stack frame.
64
+ globalMeter = null ;
65
+ // savedMeter && savedMeter[c.METER_ENTER](undefined, false);
59
66
let ret ;
60
- try {
61
- // Temporarily install the deep meter.
62
- setGlobalMeter ( deepMeter ) ;
63
- const newTarget = new . target ;
64
- if ( newTarget ) {
65
- ret = construct ( target , args , newTarget ) ;
66
- } else {
67
- ret = apply ( target , this , args ) ;
68
- }
69
- } finally {
70
- // Resume explicit metering.
71
- setGlobalMeter ( null ) ;
67
+
68
+ // Reinstall the saved meter for the actual function invocation.
69
+ globalMeter = savedMeter ;
70
+ const newTarget = new . target ;
71
+ if ( newTarget ) {
72
+ ret = construct ( target , args , newTarget ) ;
73
+ } else {
74
+ ret = apply ( target , this , args ) ;
72
75
}
73
- userMeter && userMeter [ c . METER_ALLOCATE ] ( ret ) ;
76
+
77
+ // Track the allocation of the return value.
78
+ globalMeter = null ;
79
+ savedMeter && savedMeter [ c . METER_ALLOCATE ] ( ret , false ) ;
80
+
74
81
return ret ;
75
82
} catch ( e ) {
76
- userMeter && userMeter [ c . METER_ALLOCATE ] ( e ) ;
83
+ // Track the allocation of the exception value.
84
+ globalMeter = null ;
85
+ savedMeter && savedMeter [ c . METER_ALLOCATE ] ( e , false ) ;
77
86
throw e ;
78
87
} finally {
79
- // Resume the user meter.
80
- userMeter && userMeter [ c . METER_LEAVE ] ( ) ;
81
- setGlobalMeter ( userMeter ) ;
88
+ // In case a try block consumes stack.
89
+ globalMeter = savedMeter ;
90
+ try {
91
+ // Declare we left the stack frame.
92
+ globalMeter = null ;
93
+ // savedMeter && savedMeter[c.METER_LEAVE](undefined, false);
94
+ } finally {
95
+ // Resume the saved meter, if there was one.
96
+ globalMeter = savedMeter ;
97
+ }
82
98
}
83
99
} ;
84
100
@@ -105,13 +121,19 @@ export default function tameMetering() {
105
121
}
106
122
107
123
// Override the globals with wrappers.
108
- wrap ( globalThis , null ) ;
124
+ wrap ( globalThis ) ;
109
125
110
126
// Provide a way to set the meter.
111
- setGlobalMeter = m => {
127
+ replaceGlobalMeter = m => {
112
128
const oldMeter = globalMeter ;
113
- globalMeter = m ;
129
+ if ( m !== undefined ) {
130
+ // console.log('replacing', oldMeter, 'with', m, Error('here')); // FIGME
131
+ globalMeter = m ;
132
+ }
133
+ /* if (oldMeter === null) {
134
+ console.log('returning', oldMeter, Error('here'));
135
+ } */
114
136
return oldMeter ;
115
137
} ;
116
- return setGlobalMeter ;
138
+ return replaceGlobalMeter ;
117
139
}
0 commit comments