This commit is contained in:
Dmitry Vasilev
2023-05-13 11:13:29 +03:00
parent 8bb4369ba5
commit 5310a0c2d9
4 changed files with 47 additions and 56 deletions

View File

@@ -1,15 +1,22 @@
import {set_record_call} from './runtime.js'
const get_object_to_patch = (cxt, path) => {
// Modify window object on module load
// TODO check - if modules reloaded on window reopen
// TODO - cxt.window
apply_io_patches()
// Current context for current execution of code
let cxt
export const set_current_context = _cxt => {
cxt = _cxt
}
const io_patch = (path, use_context = false) => {
let obj = cxt.window
for(let i = 0; i < path.length - 1; i++) {
obj = obj[path[i]]
}
return obj
}
const io_patch = (cxt, path, use_context = false) => {
const obj = get_object_to_patch(cxt, path)
const method = path.at(-1)
if(obj == null || obj[method] == null) {
// Method is absent in current env, skip patching
@@ -202,69 +209,40 @@ const io_patch = (cxt, path, use_context = false) => {
obj[method].__original = original
}
const io_patch_remove = (cxt, path) => {
const obj = get_object_to_patch(cxt, path)
const method = path.at(-1)
if(obj == null || obj[method] == null) {
// Method is absent in current env, skip patching
return
}
obj[method] = obj[method].__original
}
const Response_methods = [
'arrayBuffer',
'blob',
'formData',
'json',
'text',
]
// TODO bare IO functions should not be exposed at all, to allow calling it
// only from patched versions. Especially setInterval which can cause leaks
export const apply_io_patches = cxt => {
io_patch(cxt, ['Math', 'random'])
export const apply_io_patches = () => {
io_patch(['Math', 'random'])
io_patch(cxt, ['setTimeout'])
io_patch(['setTimeout'])
// TODO if call setTimeout and then clearTimeout, cache it and remove call of
// clearTimeout, and make only setTimeout, then it would never be called when
// replaying from cache
io_patch(cxt, ['clearTimeout'])
io_patch(['clearTimeout'])
// TODO patch setInterval to only cleanup all intervals on finish
const Date = cxt.window.Date
io_patch(cxt, ['Date'])
io_patch(['Date'])
cxt.window.Date.parse = Date.parse
cxt.window.Date.now = Date.now
cxt.window.Date.UTC = Date.UTC
io_patch(cxt, ['Date', 'now'])
io_patch(['Date', 'now'])
io_patch(cxt, ['fetch'])
io_patch(['fetch'])
// Check if Response is defined, for node.js
if(cxt.window.Response != null) {
const Response_methods = [
'arrayBuffer',
'blob',
'formData',
'json',
'text',
]
for(let key of Response_methods) {
io_patch(cxt, ['Response', 'prototype', key], true)
}
}
}
export const remove_io_patches = cxt => {
io_patch_remove(cxt, ['Math', 'random'])
io_patch_remove(cxt, ['setTimeout'])
io_patch_remove(cxt, ['clearTimeout'])
io_patch_remove(cxt, ['Date'])
io_patch_remove(cxt, ['fetch'])
// Check if Response is defined, for node.js
if(cxt.window.Response != null) {
for(let key of Response_methods) {
io_patch_remove(cxt, ['Response', 'prototype', key])
io_patch(['Response', 'prototype', key], true)
}
}
}

View File

@@ -1,4 +1,4 @@
import {apply_io_patches, remove_io_patches} from './record_io.js'
import {set_current_context} from './record_io.js'
/*
Converts generator-returning function to promise-returning function. Allows to
@@ -50,7 +50,7 @@ const do_run = function*(module_fns, cxt, io_cache){
}
apply_promise_patch(cxt)
apply_io_patches(cxt)
set_current_context(cxt)
for(let {module, fn} of module_fns) {
cxt.found_call = null
@@ -80,7 +80,6 @@ const do_run = function*(module_fns, cxt, io_cache){
cxt.logs = []
cxt.children = null
remove_io_patches(cxt)
remove_promise_patch(cxt)
cxt.searched_location = null
@@ -97,6 +96,10 @@ const do_run = function*(module_fns, cxt, io_cache){
}
export const run = gen_to_promise(function*(module_fns, cxt, io_cache) {
if(cxt.run_window != globalThis) {
// TODO refactor, remove cxt.run_window
throw new Error('illegal state')
}
const result = yield* do_run(module_fns, cxt, io_cache)
if(result.eval_cxt.io_cache_is_replay_aborted) {