@aptre/v86 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- package/src/virtio_net.ts +326 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#![allow(non_upper_case_globals)]
|
|
2
|
+
#![allow(static_mut_refs)]
|
|
3
|
+
|
|
4
|
+
// Safety of allow(static_mut_refs) in this file:
|
|
5
|
+
// These following two globals are not passed anywhere, only built-in function are called on them
|
|
6
|
+
static mut dirty_bitmap: Vec<u64> = Vec::new();
|
|
7
|
+
static mut dest_buffer: Vec<u32> = Vec::new();
|
|
8
|
+
|
|
9
|
+
use crate::cpu::global_pointers;
|
|
10
|
+
use crate::cpu::memory;
|
|
11
|
+
|
|
12
|
+
use std::ptr;
|
|
13
|
+
|
|
14
|
+
#[no_mangle]
|
|
15
|
+
pub unsafe fn svga_allocate_dest_buffer(size: u32) -> u32 {
|
|
16
|
+
dest_buffer.resize(size as usize, 0);
|
|
17
|
+
dest_buffer.as_mut_ptr() as u32
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub unsafe fn set_dirty_bitmap_size(size: u32) { dirty_bitmap.resize(size as usize, 0); }
|
|
21
|
+
|
|
22
|
+
pub unsafe fn mark_dirty(addr: u32) {
|
|
23
|
+
let page = (addr - memory::VGA_LFB_ADDRESS) >> 12;
|
|
24
|
+
dbg_assert!(((page >> 6) as usize) < dirty_bitmap.len());
|
|
25
|
+
*dirty_bitmap.get_unchecked_mut((page >> 6) as usize) |= 1 << (page & 63)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[no_mangle]
|
|
29
|
+
pub unsafe fn svga_mark_dirty() {
|
|
30
|
+
for v in dirty_bitmap.iter_mut() {
|
|
31
|
+
*v = u64::MAX
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn iter_dirty_pages(f: &dyn Fn(isize)) {
|
|
36
|
+
let mut min_off = u32::MAX;
|
|
37
|
+
let mut max_off = u32::MIN;
|
|
38
|
+
|
|
39
|
+
for (i, &word) in unsafe { dirty_bitmap.iter().enumerate() } {
|
|
40
|
+
if word == 0 {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
for j in 0..64 {
|
|
44
|
+
if word & 1 << j == 0 {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
let off = ((i << 6 | j) << 12) as isize;
|
|
48
|
+
dbg_assert!(off < unsafe { memory::vga_memory_size as isize });
|
|
49
|
+
if min_off == u32::MAX {
|
|
50
|
+
min_off = off as u32;
|
|
51
|
+
}
|
|
52
|
+
max_off = off as u32;
|
|
53
|
+
f(off);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
unsafe {
|
|
58
|
+
*global_pointers::svga_dirty_bitmap_min_offset = min_off;
|
|
59
|
+
*global_pointers::svga_dirty_bitmap_max_offset = max_off + 0xFFF;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#[no_mangle]
|
|
64
|
+
pub unsafe fn svga_fill_pixel_buffer(bpp: u32, svga_dest_offset: u32) {
|
|
65
|
+
let debug_bounds = false;
|
|
66
|
+
|
|
67
|
+
match bpp {
|
|
68
|
+
32 => iter_dirty_pages(&|off| {
|
|
69
|
+
dbg_assert!(off >= 0);
|
|
70
|
+
let src = memory::vga_mem8.offset(off) as *const u32;
|
|
71
|
+
let dest_offset = off / 4 - svga_dest_offset as isize;
|
|
72
|
+
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32;
|
|
73
|
+
let end = if dest_offset < 0 {
|
|
74
|
+
0
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
isize::min(1024, dest_buffer.len() as isize - dest_offset)
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
dbg_assert!(src as u32 % 8 == 0);
|
|
81
|
+
dbg_assert!(dest as u32 % 8 == 0);
|
|
82
|
+
for i in 0..end {
|
|
83
|
+
dbg_assert!(off + i < memory::vga_memory_size as isize);
|
|
84
|
+
let dword = *src.offset(i);
|
|
85
|
+
let dword = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFFFF } else { dword };
|
|
86
|
+
dbg_assert!(dest_offset + i < dest_buffer.len() as isize);
|
|
87
|
+
*dest.offset(i) = dword << 16 | dword >> 16 & 0xFF | dword & 0xFF00 | 0xFF00_0000;
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
24 => iter_dirty_pages(&|off| {
|
|
91
|
+
dbg_assert!(off >= 0 && off < memory::vga_memory_size as isize);
|
|
92
|
+
let off = off - off % 3;
|
|
93
|
+
let src = memory::vga_mem8.offset(off);
|
|
94
|
+
let dest_offset = off / 3 - svga_dest_offset as isize;
|
|
95
|
+
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32;
|
|
96
|
+
let end = if dest_offset < 0 {
|
|
97
|
+
0
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
isize::min(4096 / 3 + 1, dest_buffer.len() as isize - dest_offset)
|
|
101
|
+
};
|
|
102
|
+
for i in 0..end {
|
|
103
|
+
let dword = ptr::read_unaligned(src.offset(3 * i) as *const u32);
|
|
104
|
+
let dword = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFFFF } else { dword };
|
|
105
|
+
dbg_assert!(dest_offset + i < dest_buffer.len() as isize);
|
|
106
|
+
*dest.offset(i) = dword << 16 | dword >> 16 & 0xFF | dword & 0xFF00 | 0xFF00_0000;
|
|
107
|
+
}
|
|
108
|
+
}),
|
|
109
|
+
16 => iter_dirty_pages(&|off| {
|
|
110
|
+
dbg_assert!(off >= 0 && off + 2048 < memory::vga_memory_size as isize);
|
|
111
|
+
let src = memory::vga_mem8.offset(off) as *const u16;
|
|
112
|
+
let dest_offset = off / 2 - svga_dest_offset as isize;
|
|
113
|
+
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32;
|
|
114
|
+
let end = if dest_offset < 0 {
|
|
115
|
+
0
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
isize::min(2048, dest_buffer.len() as isize - dest_offset)
|
|
119
|
+
};
|
|
120
|
+
for i in 0..end {
|
|
121
|
+
dbg_assert!(off + i < memory::vga_memory_size as isize);
|
|
122
|
+
let word = *src.offset(i);
|
|
123
|
+
let word = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFF } else { word };
|
|
124
|
+
let r = (word & 0x1F) * 0xFF / 0x1F;
|
|
125
|
+
let g = (word >> 5 & 0x3F) * 0xFF / 0x3F;
|
|
126
|
+
let b = (word >> 11) * 0xFF / 0x1F;
|
|
127
|
+
dbg_assert!(dest_offset + i < dest_buffer.len() as isize);
|
|
128
|
+
*dest.offset(i) = (r as u32) << 16 | (g as u32) << 8 | b as u32 | 0xFF00_0000;
|
|
129
|
+
}
|
|
130
|
+
}),
|
|
131
|
+
15 => iter_dirty_pages(&|off| {
|
|
132
|
+
dbg_assert!(off >= 0 && off + 2048 < memory::vga_memory_size as isize);
|
|
133
|
+
let src = memory::vga_mem8.offset(off) as *const u16;
|
|
134
|
+
let dest_offset = off / 2 - svga_dest_offset as isize;
|
|
135
|
+
let dest = dest_buffer.as_mut_ptr().offset(dest_offset) as *mut u32;
|
|
136
|
+
let end = if dest_offset < 0 {
|
|
137
|
+
0
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
isize::min(2048, dest_buffer.len() as isize - dest_offset)
|
|
141
|
+
};
|
|
142
|
+
for i in 0..end {
|
|
143
|
+
dbg_assert!(off + i < memory::vga_memory_size as isize);
|
|
144
|
+
let word = *src.offset(i);
|
|
145
|
+
let word = if debug_bounds && (i == 0 || i == end - 1) { 0xFFFF } else { word };
|
|
146
|
+
let r = (word & 0x1F) * 0xFF / 0x1F;
|
|
147
|
+
let g = (word >> 5 & 0x1F) * 0xFF / 0x1F;
|
|
148
|
+
let b = (word >> 10 & 0x1F) * 0xFF / 0x1F;
|
|
149
|
+
dbg_assert!(dest_offset + i < dest_buffer.len() as isize);
|
|
150
|
+
*dest.offset(i) = (r as u32) << 16 | (g as u32) << 8 | b as u32 | 0xFF00_0000;
|
|
151
|
+
}
|
|
152
|
+
}),
|
|
153
|
+
_ => {
|
|
154
|
+
dbg_log!("{}", bpp);
|
|
155
|
+
dbg_assert!(false, "Unsupported bpp");
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
//if cfg!(debug_assertions) {
|
|
160
|
+
// let mut pages = 0;
|
|
161
|
+
// for &word in dirty_bitmap.iter() {
|
|
162
|
+
// pages += word.count_ones();
|
|
163
|
+
// }
|
|
164
|
+
// dbg_log!(
|
|
165
|
+
// "fill offset={:x} bpp={} pages={}",
|
|
166
|
+
// svga_dest_offset,
|
|
167
|
+
// bpp,
|
|
168
|
+
// pages,
|
|
169
|
+
// );
|
|
170
|
+
//}
|
|
171
|
+
|
|
172
|
+
for v in dirty_bitmap.iter_mut() {
|
|
173
|
+
*v = 0
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
use crate::cpu::memory;
|
|
2
|
+
use crate::prefix::{PREFIX_MASK_ADDRSIZE, PREFIX_MASK_OPSIZE};
|
|
3
|
+
use crate::state_flags::CachedStateFlags;
|
|
4
|
+
|
|
5
|
+
#[derive(Clone)]
|
|
6
|
+
pub struct CpuContext {
|
|
7
|
+
pub eip: u32,
|
|
8
|
+
pub prefixes: u8,
|
|
9
|
+
pub cs_offset: u32,
|
|
10
|
+
pub state_flags: CachedStateFlags,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
impl CpuContext {
|
|
14
|
+
pub fn advance16(&mut self) {
|
|
15
|
+
dbg_assert!(self.eip & 0xFFF < 0xFFE);
|
|
16
|
+
self.eip += 2;
|
|
17
|
+
}
|
|
18
|
+
pub fn advance32(&mut self) {
|
|
19
|
+
dbg_assert!(self.eip & 0xFFF < 0xFFC);
|
|
20
|
+
self.eip += 4;
|
|
21
|
+
}
|
|
22
|
+
#[allow(unused)]
|
|
23
|
+
pub fn advance_moffs(&mut self) {
|
|
24
|
+
if self.asize_32() {
|
|
25
|
+
self.advance32()
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
self.advance16()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn read_imm8(&mut self) -> u8 {
|
|
33
|
+
dbg_assert!(self.eip & 0xFFF < 0xFFF);
|
|
34
|
+
let v = memory::read8(self.eip) as u8;
|
|
35
|
+
self.eip += 1;
|
|
36
|
+
v
|
|
37
|
+
}
|
|
38
|
+
pub fn read_imm8s(&mut self) -> i8 { self.read_imm8() as i8 }
|
|
39
|
+
pub fn read_imm16(&mut self) -> u16 {
|
|
40
|
+
dbg_assert!(self.eip & 0xFFF < 0xFFE);
|
|
41
|
+
let v = memory::read16(self.eip) as u16;
|
|
42
|
+
self.eip += 2;
|
|
43
|
+
v
|
|
44
|
+
}
|
|
45
|
+
pub fn read_imm32(&mut self) -> u32 {
|
|
46
|
+
dbg_assert!(self.eip & 0xFFF < 0xFFC);
|
|
47
|
+
let v = memory::read32s(self.eip) as u32;
|
|
48
|
+
self.eip += 4;
|
|
49
|
+
v
|
|
50
|
+
}
|
|
51
|
+
pub fn read_moffs(&mut self) -> u32 {
|
|
52
|
+
if self.asize_32() {
|
|
53
|
+
self.read_imm32()
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
self.read_imm16() as u32
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
pub fn cpl3(&self) -> bool { self.state_flags.cpl3() }
|
|
61
|
+
pub fn has_flat_segmentation(&self) -> bool { self.state_flags.has_flat_segmentation() }
|
|
62
|
+
pub fn osize_32(&self) -> bool {
|
|
63
|
+
self.state_flags.is_32() != (self.prefixes & PREFIX_MASK_OPSIZE != 0)
|
|
64
|
+
}
|
|
65
|
+
pub fn asize_32(&self) -> bool {
|
|
66
|
+
self.state_flags.is_32() != (self.prefixes & PREFIX_MASK_ADDRSIZE != 0)
|
|
67
|
+
}
|
|
68
|
+
pub fn ssize_32(&self) -> bool { self.state_flags.ssize_32() }
|
|
69
|
+
}
|
package/src/rust/dbg.rs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#[allow(dead_code)]
|
|
2
|
+
pub const DEBUG: bool = cfg!(debug_assertions);
|
|
3
|
+
|
|
4
|
+
#[cfg(target_arch = "wasm32")]
|
|
5
|
+
extern "C" {
|
|
6
|
+
pub fn log_from_wasm(ptr: *const u8, len: usize);
|
|
7
|
+
pub fn console_log_from_wasm(ptr: *const u8, len: usize);
|
|
8
|
+
pub fn dbg_trace_from_wasm();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#[cfg(target_arch = "wasm32")]
|
|
12
|
+
pub fn log_to_js_console<T: std::string::ToString>(s: T) {
|
|
13
|
+
let s = s.to_string();
|
|
14
|
+
let len = s.len();
|
|
15
|
+
unsafe {
|
|
16
|
+
log_from_wasm(s.as_bytes().as_ptr(), len);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[cfg(target_arch = "wasm32")]
|
|
21
|
+
pub fn console_log_to_js_console<T: std::string::ToString>(s: T) {
|
|
22
|
+
let s = s.to_string();
|
|
23
|
+
let len = s.len();
|
|
24
|
+
unsafe {
|
|
25
|
+
console_log_from_wasm(s.as_bytes().as_ptr(), len);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[cfg(target_arch = "wasm32")]
|
|
30
|
+
pub fn dbg_trace() {
|
|
31
|
+
if DEBUG {
|
|
32
|
+
unsafe {
|
|
33
|
+
dbg_trace_from_wasm();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
39
|
+
pub fn dbg_trace() {}
|
|
40
|
+
|
|
41
|
+
#[allow(unused_macros)]
|
|
42
|
+
macro_rules! dbg_log {
|
|
43
|
+
($fmt:expr) => {
|
|
44
|
+
println!($fmt);
|
|
45
|
+
};
|
|
46
|
+
($fmt:expr, $($arg:tt)*) => {
|
|
47
|
+
println!($fmt, $($arg)*);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#[allow(unused_macros)]
|
|
52
|
+
macro_rules! console_log {
|
|
53
|
+
($fmt:expr) => {
|
|
54
|
+
println!($fmt);
|
|
55
|
+
};
|
|
56
|
+
($fmt:expr, $($arg:tt)*) => {
|
|
57
|
+
println!($fmt, $($arg)*);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#[allow(unused_macros)]
|
|
62
|
+
macro_rules! dbg_assert {
|
|
63
|
+
($($arg:tt)*) => {
|
|
64
|
+
debug_assert!($($arg)*)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#[cfg(target_arch = "wasm32")]
|
|
69
|
+
#[allow(unused_macros)]
|
|
70
|
+
macro_rules! console_log {
|
|
71
|
+
($fmt:expr) => {
|
|
72
|
+
{
|
|
73
|
+
crate::dbg::console_log_to_js_console($fmt);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
($fmt:expr, $($arg:tt)*) => {
|
|
77
|
+
{
|
|
78
|
+
crate::dbg::console_log_to_js_console(format!($fmt, $($arg)*));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#[cfg(target_arch = "wasm32")]
|
|
84
|
+
#[allow(unused_macros)]
|
|
85
|
+
macro_rules! dbg_log {
|
|
86
|
+
($fmt:expr) => {
|
|
87
|
+
{
|
|
88
|
+
use crate::dbg::{ DEBUG, log_to_js_console };
|
|
89
|
+
if DEBUG { log_to_js_console($fmt); }
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
($fmt:expr, $($arg:tt)*) => {
|
|
93
|
+
{
|
|
94
|
+
use crate::dbg::{ DEBUG, log_to_js_console };
|
|
95
|
+
if DEBUG { log_to_js_console(format!($fmt, $($arg)*)); }
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|