refactor record io move cxt to window

This commit is contained in:
Dmitry Vasilev
2024-02-14 13:36:51 +08:00
parent b473e8b66e
commit 0d902418ee
2 changed files with 37 additions and 43 deletions

View File

@@ -1,28 +1,7 @@
import {set_record_call} from './runtime.js' import {set_record_call} from './runtime.js'
// Current context for current execution of code const io_patch = (window, path, use_context = false) => {
let cxt let obj = window
const label = Symbol('io_patches_applied')
export const set_current_context = _cxt => {
cxt = _cxt
// When we develop leporello.js inside itself, patches may be applied twice,
// once for host leporello, and another for leporello under development. This
// module would be loaded twice, once from host window, another time from
// app_window. Every module will have its own 'label', so we can apply
// patches twice
if(cxt.window.__io_patched_by == null) {
cxt.window.__io_patched_by = new Set()
}
if(!cxt.window.__io_patched_by.has(label)) {
apply_io_patches()
cxt.window.__io_patched_by.add(label)
}
}
const io_patch = (path, use_context = false) => {
let obj = cxt.window
for(let i = 0; i < path.length - 1; i++) { for(let i = 0; i < path.length - 1; i++) {
obj = obj[path[i]] obj = obj[path[i]]
} }
@@ -35,13 +14,16 @@ const io_patch = (path, use_context = false) => {
const original = obj[method] const original = obj[method]
obj[method] = make_patched_method(original, name, use_context) obj[method] = make_patched_method(window, original, name, use_context)
obj[method].__original = original obj[method].__original = original
} }
const make_patched_method = (original, name, use_context) => { const make_patched_method = (window, original, name, use_context) => {
const method = function(...args) { const method = function(...args) {
const cxt = window.__cxt
if(cxt.io_trace_is_replay_aborted) { if(cxt.io_trace_is_replay_aborted) {
// Try to finish fast // Try to finish fast
const error = new Error('io replay was aborted') const error = new Error('io replay was aborted')
@@ -243,10 +225,10 @@ const make_patched_method = (original, name, use_context) => {
return method return method
} }
const patch_Date = () => { const patch_Date = (window) => {
const Date = cxt.window.Date const Date = window.Date
const Date_patched = make_patched_method(Date, 'Date', false) const Date_patched = make_patched_method(window, Date, 'Date', false)
cxt.window.Date = function(...args) { window.Date = function(...args) {
if(args.length == 0) { if(args.length == 0) {
// return current Date, IO operation // return current Date, IO operation
if(new.target != null) { if(new.target != null) {
@@ -263,28 +245,40 @@ const patch_Date = () => {
} }
} }
} }
cxt.window.Date.__original = Date window.Date.__original = Date
cxt.window.Date.parse = Date.parse window.Date.parse = Date.parse
cxt.window.Date.now = Date.now window.Date.now = Date.now
cxt.window.Date.UTC = Date.UTC window.Date.UTC = Date.UTC
io_patch(['Date', 'now']) io_patch(window, ['Date', 'now'])
} }
export const apply_io_patches = () => { export const apply_io_patches = (cxt) => {
io_patch(['Math', 'random']) const window = cxt.window
io_patch(['setTimeout']) // set current context
window.__cxt = cxt
if(cxt.window.__io_patched) {
// Patches already applied, do nothing
return
} else {
cxt.window.__io_patched = true
}
io_patch(window, ['Math', 'random'])
io_patch(window, ['setTimeout'])
// TODO if call setTimeout and then clearTimeout, trace it and remove call of // TODO if call setTimeout and then clearTimeout, trace it and remove call of
// clearTimeout, and make only setTimeout, then it would never be called when // clearTimeout, and make only setTimeout, then it would never be called when
// replaying from trace // replaying from trace
io_patch(['clearTimeout']) io_patch(window, ['clearTimeout'])
// TODO patch setInterval to only cleanup all intervals on finish // TODO patch setInterval to only cleanup all intervals on finish
patch_Date() patch_Date(window)
io_patch(['fetch']) io_patch(window, ['fetch'])
// Check if Response is defined, for node.js // Check if Response is defined, for node.js
if(cxt.window.Response != null) { if(cxt.window.Response != null) {
const Response_methods = [ const Response_methods = [
@@ -295,7 +289,7 @@ export const apply_io_patches = () => {
'text', 'text',
] ]
for(let key of Response_methods) { for(let key of Response_methods) {
io_patch(['Response', 'prototype', key], true) io_patch(window, ['Response', 'prototype', key], true)
} }
} }
} }

View File

@@ -1,4 +1,4 @@
import {set_current_context} from './record_io.js' import {apply_io_patches} from './record_io.js'
import {LetMultiversion} from './let_multiversion.js' import {LetMultiversion} from './let_multiversion.js'
import {defineMultiversionArray, create_array, wrap_array} from './array.js' import {defineMultiversionArray, create_array, wrap_array} from './array.js'
import {create_object} from './object.js' import {create_object} from './object.js'
@@ -73,7 +73,7 @@ const do_run = function*(module_fns, cxt, io_trace){
defineMultiversion(cxt.window) defineMultiversion(cxt.window)
apply_promise_patch(cxt) apply_promise_patch(cxt)
set_current_context(cxt) apply_io_patches(cxt)
for(let i = 0; i < module_fns.length; i++) { for(let i = 0; i < module_fns.length; i++) {
const {module, fn} = module_fns[i] const {module, fn} = module_fns[i]