This commit is contained in:
Dmitry Vasilev
2023-02-07 23:07:37 +08:00
parent 131c0565f1
commit 4119c52413
4 changed files with 54 additions and 38 deletions

View File

@@ -130,9 +130,17 @@ there is cached result.
Builtin IO functions are mocked to cache IO. Current list of builtin cached Builtin IO functions are mocked to cache IO. Current list of builtin cached
functions is: functions is:
- `Date` constructor - `Date`
- `Math.random()` - `Math.random()`
- `fetch` - `fetch`
- `Response` methods:
- `arrayBuffer`
- `blob`
- `formData`
- `json`
- `text`
- `setTimeout`
- `clearTimeout`
If you want to make your own own function IO-caching, or import third party If you want to make your own own function IO-caching, or import third party
function and make it IO-caching, then you should use `IO` pragma. function and make it IO-caching, then you should use `IO` pragma.

View File

@@ -768,6 +768,11 @@ const on_deferred_call = (state, call, calltree_changed_token, logs) => {
} }
} }
// TODO test
const clear_io_cache = state => {
return run_code({...state, io_cache: null})
}
const do_load_dir = (state, dir) => { const do_load_dir = (state, dir) => {
const collect_files = dir => dir.kind == 'file' const collect_files = dir => dir.kind == 'file'
? [dir] ? [dir]
@@ -848,5 +853,6 @@ export const COMMANDS = {
external_imports_loaded, external_imports_loaded,
eval_modules_finished, eval_modules_finished,
on_deferred_call, on_deferred_call,
clear_io_cache,
calltree: calltree_commands, calltree: calltree_commands,
} }

View File

@@ -20,7 +20,11 @@ const io_patch = (cxt, path, use_context = false) => {
const original = obj[method] const original = obj[method]
obj[method] = function(...args) { obj[method] = function(...args) {
// TODO guard calls from prev run // TODO if called from previous version of code (calltree_changed_token is
// different), then do not call IO function and throw error to finish
// previous run ASAP
// TODO remove
console.error('patched method', name, { console.error('patched method', name, {
io_cache_is_recording: cxt.io_cache_is_recording, io_cache_is_recording: cxt.io_cache_is_recording,
io_cache_is_replay_aborted: cxt.io_cache_is_replay_aborted, io_cache_is_replay_aborted: cxt.io_cache_is_replay_aborted,
@@ -28,14 +32,18 @@ const io_patch = (cxt, path, use_context = false) => {
? cxt.io_cache.length ? cxt.io_cache.length
: cxt.io_cache_index : cxt.io_cache_index
}) })
// TODO guard that in find_call io methods are not called?
// if(searched_location != null) { // sanity check
// throw new Error('illegal state') if(cxt.searched_location != null) {
// } throw new Error('illegal state')
}
if(cxt.io_cache_is_replay_aborted) { if(cxt.io_cache_is_replay_aborted) {
// Try to finish fast // Try to finish fast
throw new Error('io replay aborted') throw new Error('io replay aborted')
} else if(cxt.io_cache_is_recording) { }
if(cxt.io_cache_is_recording) {
let ok, value, error let ok, value, error
const has_new_target = new.target != null const has_new_target = new.target != null
try { try {
@@ -141,6 +149,11 @@ const io_patch = (cxt, path, use_context = false) => {
cxt.io_cache_resolver_is_set = true cxt.io_cache_resolver_is_set = true
original_setTimeout(() => { original_setTimeout(() => {
if(cxt.io_cache_is_replay_aborted) {
console.error('RESOLVER ABORTED')
return
}
// TODO guard from previous run // TODO guard from previous run
console.error('resolver', { console.error('resolver', {
io_cache_is_replay_aborted: cxt.io_cache_is_replay_aborted, io_cache_is_replay_aborted: cxt.io_cache_is_replay_aborted,
@@ -151,38 +164,32 @@ const io_patch = (cxt, path, use_context = false) => {
// TODO check if call from prev run // TODO check if call from prev run
if(cxt.io_cache_is_replay_aborted) { // Sanity check
console.error('RESOLVER ABORTED') if(cxt.io_cache_index >= cxt.io_cache.length) {
return throw new Error('illegal state')
} }
if(cxt.io_cache_index >= cxt.io_cache.length) { const next_event = cxt.io_cache[cxt.io_cache_index]
// TODO Do nothing or what? if(next_event.type == 'call') {
// Should not gonna happen // TODO Call not happened, replay?
throw new Error('illegal state') cxt.io_cache_is_replay_aborted = true
} else { } else {
const next_event = cxt.io_cache[cxt.io_cache_index] while(
if(next_event.type == 'call') { cxt.io_cache_index < cxt.io_cache.length
// TODO Call not happened, replay? &&
cxt.io_cache_is_replay_aborted = true cxt.io_cache[cxt.io_cache_index].type == 'resolution'
} else { ) {
while( const resolution = cxt.io_cache[cxt.io_cache_index]
cxt.io_cache_index < cxt.io_cache.length const resolver = cxt.io_cache_resolvers.get(resolution.index)
&&
cxt.io_cache[cxt.io_cache_index].type == 'resolution'
) {
const resolution = cxt.io_cache[cxt.io_cache_index]
const resolver = cxt.io_cache_resolvers.get(resolution.index)
cxt.io_cache_index++ cxt.io_cache_index++
if(cxt.io_cache[resolution.index].name == 'setTimeout') { if(cxt.io_cache[resolution.index].name == 'setTimeout') {
resolver() resolver()
} else { } else {
resolver(cxt.io_cache[resolution.index].value) resolver(cxt.io_cache[resolution.index].value)
}
console.log('RESOLVE', cxt.io_cache_index, resolution.index)
} }
console.log('RESOLVE', cxt.io_cache_index, resolution.index)
} }
} }
@@ -192,9 +199,6 @@ const io_patch = (cxt, path, use_context = false) => {
cxt.io_cache_index++ cxt.io_cache_index++
if(call.ok) { if(call.ok) {
// TODO resolve promises in the same order they were resolved on
// initial execution
if(call.value instanceof cxt.window.Promise) { if(call.value instanceof cxt.window.Promise) {
return new Promise(resolve => { return new Promise(resolve => {
cxt.io_cache_resolvers.set(cxt.io_cache_index - 1, resolve) cxt.io_cache_resolvers.set(cxt.io_cache_index - 1, resolve)

View File

@@ -3127,8 +3127,6 @@ const y = x()`
console.log(await delay(0)) console.log(await delay(0))
` `
console.log('CODE2', code2.slice(75))
const next = await command_input_async(i, code2, 0) const next = await command_input_async(i, code2, 0)
// Assert cache was used // Assert cache was used