Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4497833
engine.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
46 KB
Referenced Files
None
Subscribers
None
engine.c
View Options
#include
"gc.h"
#include
"errors.h"
#include
<stdlib.h>
#include
"silver/engine.h"
#include
"silver/swarm.h"
#include
"ops/literals.h"
#include
"ops/stack.h"
#include
"ops/locals.h"
#include
"ops/upvalues.h"
#include
"ops/globals.h"
#include
"ops/property.h"
#include
"ops/optional.h"
#include
"ops/private.h"
#include
"ops/super.h"
#include
"ops/arithmetic.h"
#include
"ops/comparison.h"
#include
"ops/bitwise.h"
#include
"ops/unary.h"
#include
"ops/control.h"
#include
"ops/calls.h"
#include
"ops/returns.h"
#include
"ops/exceptions.h"
#include
"ops/async.h"
#include
"ops/iteration.h"
#include
"ops/objects.h"
#include
"ops/coercion.h"
sv_vm_t
*
sv_vm_create
(
ant_t
*
js
,
sv_vm_kind_t
kind
)
{
int
stack_size
,
max_frames
;
sv_vm_limits
(
kind
,
&
stack_size
,
&
max_frames
);
sv_vm_t
*
vm
=
calloc
(
1
,
sizeof
(
*
vm
));
if
(
!
vm
)
return
NULL
;
vm
->
js
=
js
;
vm
->
stack_size
=
stack_size
;
vm
->
stack
=
calloc
((
size_t
)
stack_size
,
sizeof
(
ant_value_t
));
vm
->
max_frames
=
max_frames
;
vm
->
frames
=
calloc
((
size_t
)
max_frames
,
sizeof
(
sv_frame_t
));
if
(
!
vm
->
stack
||
!
vm
->
frames
)
{
sv_vm_destroy
(
vm
);
return
NULL
;
}
return
vm
;
}
void
sv_vm_destroy
(
sv_vm_t
*
vm
)
{
if
(
!
vm
)
return
;
free
(
vm
->
stack
);
free
(
vm
->
frames
);
free
(
vm
);
}
static
bool
sv_vm_grow_frames
(
sv_vm_t
*
vm
)
{
int
new_max
=
vm
->
max_frames
*
2
;
if
(
new_max
>
SV_FRAMES_HARD_MAX
)
new_max
=
SV_FRAMES_HARD_MAX
;
if
(
new_max
<=
vm
->
max_frames
)
return
false
;
sv_frame_t
*
nf
=
realloc
(
vm
->
frames
,
(
size_t
)
new_max
*
sizeof
(
sv_frame_t
));
if
(
!
nf
)
return
false
;
vm
->
frames
=
nf
;
vm
->
max_frames
=
new_max
;
return
true
;
}
static
bool
sv_vm_grow_stack
(
sv_vm_t
*
vm
)
{
int
new_size
=
vm
->
stack_size
*
2
;
if
(
new_size
>
SV_STACK_HARD_MAX
)
new_size
=
SV_STACK_HARD_MAX
;
if
(
new_size
<=
vm
->
stack_size
)
return
false
;
ant_value_t
*
old
=
vm
->
stack
;
ant_value_t
*
ns
=
realloc
(
vm
->
stack
,
(
size_t
)
new_size
*
sizeof
(
ant_value_t
));
if
(
!
ns
)
return
false
;
ptrdiff_t
delta
=
ns
-
old
;
vm
->
stack
=
ns
;
vm
->
stack_size
=
new_size
;
if
(
delta
!=
0
)
{
for
(
int
i
=
0
;
i
<=
vm
->
fp
;
i
++
)
{
if
(
vm
->
frames
[
i
].
bp
)
vm
->
frames
[
i
].
bp
+=
delta
;
if
(
vm
->
frames
[
i
].
lp
)
vm
->
frames
[
i
].
lp
+=
delta
;
}
for
(
sv_upvalue_t
*
uv
=
vm
->
open_upvalues
;
uv
;
uv
=
uv
->
next
)
{
if
(
uv
->
location
!=
&
uv
->
closed
)
uv
->
location
+=
delta
;
}
}
return
true
;
}
bool
sv_lookup_srcpos
(
sv_func_t
*
func
,
int
bc_offset
,
uint32_t
*
line
,
uint32_t
*
col
)
{
if
(
!
func
||
!
func
->
srcpos
||
func
->
srcpos_count
<=
0
)
return
false
;
int
best
=
-1
;
for
(
int
i
=
0
;
i
<
func
->
srcpos_count
;
i
++
)
{
if
((
int
)
func
->
srcpos
[
i
].
bc_offset
<=
bc_offset
)
best
=
i
;
else
break
;
}
if
(
best
<
0
)
return
false
;
if
(
line
)
*
line
=
func
->
srcpos
[
best
].
line
;
if
(
col
)
*
col
=
func
->
srcpos
[
best
].
col
;
return
true
;
}
bool
sv_lookup_srcspan
(
sv_func_t
*
func
,
int
bc_offset
,
uint32_t
*
src_off
,
uint32_t
*
src_end
)
{
if
(
!
func
||
!
func
->
srcpos
||
func
->
srcpos_count
<=
0
)
return
false
;
int
best
=
-1
;
for
(
int
i
=
0
;
i
<
func
->
srcpos_count
;
i
++
)
{
if
((
int
)
func
->
srcpos
[
i
].
bc_offset
<=
bc_offset
)
best
=
i
;
else
break
;
}
if
(
best
<
0
)
return
false
;
uint32_t
off
=
func
->
srcpos
[
best
].
src_off
;
uint32_t
end
=
func
->
srcpos
[
best
].
src_end
;
if
(
end
<
off
)
end
=
off
;
if
(
src_off
)
*
src_off
=
off
;
if
(
src_end
)
*
src_end
=
end
;
return
true
;
}
static
ant_offset_t
sv_srcpos_to_offset_local
(
const
char
*
code
,
ant_offset_t
clen
,
uint32_t
line
,
uint32_t
col
)
{
ant_offset_t
off
=
0
;
uint32_t
cur
=
1
;
while
(
off
<
clen
&&
cur
<
line
)
{
if
(
code
[
off
]
==
'\n'
)
cur
++
;
off
++
;
}
if
(
col
>
0
)
off
+=
col
-
1
;
if
(
off
>
clen
)
off
=
clen
;
return
off
;
}
void
js_set_error_site_from_bc
(
ant_t
*
js
,
sv_func_t
*
func
,
int
bc_offset
,
const
char
*
filename
)
{
if
(
!
js
||
!
func
||
!
func
->
source
||
func
->
source_len
<=
0
)
return
;
uint32_t
src_off
=
0
,
src_end
=
0
;
if
(
sv_lookup_srcspan
(
func
,
bc_offset
,
&
src_off
,
&
src_end
))
{
ant_offset_t
off
=
(
ant_offset_t
)
src_off
;
ant_offset_t
span_len
=
(
ant_offset_t
)(
src_end
>
src_off
?
(
src_end
-
src_off
)
:
0
);
if
(
span_len
<=
0
&&
off
<
(
ant_offset_t
)
func
->
source_len
)
span_len
=
1
;
js_set_error_site
(
js
,
func
->
source
,
(
ant_offset_t
)
func
->
source_len
,
filename
?
filename
:
func
->
filename
,
off
,
span_len
);
return
;
}
uint32_t
line
=
0
,
col
=
0
;
if
(
sv_lookup_srcpos
(
func
,
bc_offset
,
&
line
,
&
col
))
{
ant_offset_t
off
=
sv_srcpos_to_offset_local
(
func
->
source
,
(
ant_offset_t
)
func
->
source_len
,
line
,
col
);
js_set_error_site
(
js
,
func
->
source
,
(
ant_offset_t
)
func
->
source_len
,
filename
?
filename
:
func
->
filename
,
off
,
0
);
}
}
void
js_set_error_site_from_vm_top
(
ant_t
*
js
)
{
if
(
!
js
||
!
js
->
vm
||
js
->
vm
->
fp
<
0
)
return
;
sv_frame_t
*
frame
=
&
js
->
vm
->
frames
[
js
->
vm
->
fp
];
sv_func_t
*
func
=
frame
->
func
;
if
(
!
func
)
return
;
int
bc_off
=
0
;
if
(
frame
->
ip
&&
func
->
code
)
bc_off
=
(
int
)(
frame
->
ip
-
func
->
code
);
js_set_error_site_from_bc
(
js
,
func
,
bc_off
,
func
->
filename
);
}
void
sv_vm_visit_frame_funcs
(
sv_vm_t
*
vm
,
void
(
*
visitor
)(
void
*
,
sv_func_t
*
),
void
*
ctx
)
{
if
(
!
vm
)
return
;
for
(
int
i
=
0
;
i
<=
vm
->
fp
;
i
++
)
if
(
vm
->
frames
[
i
].
func
)
visitor
(
ctx
,
vm
->
frames
[
i
].
func
);
}
ant_value_t
sv_call_async_closure_dispatch
(
sv_vm_t
*
vm
,
ant_t
*
js
,
sv_closure_t
*
closure
,
ant_value_t
callee_func
,
ant_value_t
super_val
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
argc
)
{
return
sv_start_async_closure
(
vm
,
js
,
closure
,
callee_func
,
super_val
,
this_val
,
args
,
argc
);
}
ant_value_t
sv_execute_entry_tla
(
ant_t
*
js
,
sv_func_t
*
func
,
ant_value_t
this_val
)
{
return
sv_start_tla
(
js
,
func
,
this_val
);
}
static
inline
ant_value_t
sv_stage_frame_args
(
sv_vm_t
*
vm
,
ant_t
*
js
,
sv_func_t
*
func
,
ant_value_t
*
args
,
int
argc
,
ant_value_t
**
out_bp
,
ant_value_t
**
out_lp
)
{
int
arg_slots
=
(
argc
>
func
->
param_count
)
?
argc
:
func
->
param_count
;
int
need
=
arg_slots
+
func
->
max_locals
;
if
(
vm
->
sp
+
need
>
vm
->
stack_size
)
{
int
args_idx
=
(
args
&&
args
>=
vm
->
stack
&&
args
<
vm
->
stack
+
vm
->
stack_size
)
?
(
int
)(
args
-
vm
->
stack
)
:
-1
;
while
(
vm
->
sp
+
need
>
vm
->
stack_size
)
{
if
(
!
sv_vm_grow_stack
(
vm
))
return
js_mkerr
(
js
,
"stack overflow"
);
}
if
(
args_idx
>=
0
)
args
=
&
vm
->
stack
[
args_idx
];
}
ant_value_t
*
base
=
&
vm
->
stack
[
vm
->
sp
];
*
out_bp
=
base
;
*
out_lp
=
base
+
arg_slots
;
if
(
argc
>
0
&&
args
)
memmove
(
base
,
args
,
(
size_t
)
argc
*
sizeof
(
ant_value_t
));
for
(
int
i
=
argc
;
i
<
arg_slots
;
i
++
)
base
[
i
]
=
js_mkundef
();
if
(
func
->
max_locals
>
0
)
for
(
int
i
=
0
;
i
<
func
->
max_locals
;
i
++
)
(
*
out_lp
)[
i
]
=
js_mkundef
();
vm
->
sp
+=
need
;
return
js_mkundef
();
}
static
inline
ant_value_t
sv_execute_entry_common
(
sv_vm_t
*
vm
,
sv_func_t
*
func
,
sv_upvalue_t
**
upvalues
,
int
upvalue_count
,
ant_value_t
callee_func
,
ant_value_t
super_val
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
argc
,
ant_value_t
*
out_this
)
{
if
(
!
vm
||
!
vm
->
js
||
!
func
)
return
mkval
(
T_ERR
,
0
);
ant_t
*
js
=
vm
->
js
;
if
(
vm
->
fp
+
1
>=
vm
->
max_frames
&&
!
sv_vm_grow_frames
(
vm
))
return
js_mkerr_typed
(
js
,
JS_ERR_RANGE
|
JS_ERR_NO_STACK
,
"Maximum AOT call stack size exceeded"
);
int
saved_fp
=
vm
->
fp
;
vm
->
fp
=
saved_fp
+
1
;
vm
->
frames
[
vm
->
fp
].
upvalues
=
upvalues
;
vm
->
frames
[
vm
->
fp
].
upvalue_count
=
upvalue_count
;
vm
->
frames
[
vm
->
fp
].
callee
=
callee_func
;
ant_value_t
result
=
sv_execute_frame
(
vm
,
func
,
this_val
,
super_val
,
args
,
argc
);
if
(
out_this
)
*
out_this
=
vm
->
frames
[
vm
->
fp
].
this
;
vm
->
fp
=
saved_fp
;
return
result
;
}
ant_value_t
sv_execute_entry
(
sv_vm_t
*
vm
,
sv_func_t
*
func
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
argc
)
{
return
sv_execute_entry_common
(
vm
,
func
,
NULL
,
0
,
js_mkundef
(),
js_mkundef
(),
this_val
,
args
,
argc
,
NULL
);
}
ant_value_t
sv_execute_closure_entry
(
sv_vm_t
*
vm
,
sv_closure_t
*
closure
,
ant_value_t
callee_func
,
ant_value_t
super_val
,
ant_value_t
this_val
,
ant_value_t
*
args
,
int
argc
,
ant_value_t
*
out_this
)
{
if
(
!
closure
||
!
closure
->
func
)
return
mkval
(
T_ERR
,
0
);
return
sv_execute_entry_common
(
vm
,
closure
->
func
,
closure
->
upvalues
,
closure
->
func
->
upvalue_count
,
callee_func
,
super_val
,
this_val
,
args
,
argc
,
out_this
);
}
ant_value_t
sv_execute_frame
(
sv_vm_t
*
vm
,
sv_func_t
*
func
,
ant_value_t
this
,
ant_value_t
super_val
,
ant_value_t
*
args
,
int
argc
)
{
ant_t
*
js
=
vm
->
js
;
uint8_t
*
ip
=
func
->
code
;
int
entry_fp
=
vm
->
fp
;
ant_value_t
vm_result
=
js_mkundef
();
// TODO: shorthand?
sv_frame_t
*
frame
=
&
vm
->
frames
[
vm
->
fp
];
frame
->
ip
=
ip
;
frame
->
func
=
func
;
frame
->
this
=
sv_normalize_this_for_frame
(
js
,
func
,
this
);
frame
->
new_target
=
js
->
new_target
;
frame
->
super_val
=
super_val
;
frame
->
prev_sp
=
vm
->
sp
;
frame
->
handler_base
=
vm
->
handler_depth
;
frame
->
handler_top
=
vm
->
handler_depth
;
frame
->
argc
=
argc
;
frame
->
completion
.
kind
=
SV_COMPLETION_NONE
;
frame
->
completion
.
value
=
js_mkundef
();
frame
->
with_obj
=
js_mkundef
();
ant_value_t
*
entry_bp
=
NULL
;
ant_value_t
*
entry_lp
=
NULL
;
ant_value_t
stage_err
=
sv_stage_frame_args
(
vm
,
js
,
func
,
args
,
argc
,
&
entry_bp
,
&
entry_lp
);
if
(
is_err
(
stage_err
))
{
vm_result
=
stage_err
;
goto
sv_leave
;
}
#ifdef ANT_JIT
if
(
vm
->
jit_resume
.
active
)
{
ip
=
func
->
code
+
vm
->
jit_resume
.
ip_offset
;
frame
->
ip
=
ip
;
int64_t
rl
=
vm
->
jit_resume
.
n_locals
<
func
->
max_locals
?
vm
->
jit_resume
.
n_locals
:
func
->
max_locals
;
for
(
int64_t
i
=
0
;
i
<
rl
;
i
++
)
entry_lp
[
i
]
=
vm
->
jit_resume
.
locals
[
i
];
ant_value_t
*
old_lp
=
vm
->
jit_resume
.
locals
;
for
(
sv_upvalue_t
*
uv
=
vm
->
open_upvalues
;
uv
;
uv
=
uv
->
next
)
{
if
(
uv
->
location
>=
old_lp
&&
uv
->
location
<
old_lp
+
rl
)
{
ptrdiff_t
slot
=
uv
->
location
-
old_lp
;
uv
->
location
=
&
entry_lp
[
slot
];
}}
}
#endif
frame
->
bp
=
entry_bp
;
frame
->
lp
=
entry_lp
;
ant_value_t
*
bp
=
frame
->
bp
;
ant_value_t
*
lp
=
frame
->
lp
;
#ifdef ANT_JIT
if
(
vm
->
jit_resume
.
active
)
{
for
(
int64_t
i
=
0
;
i
<
vm
->
jit_resume
.
vstack_sp
;
i
++
)
vm
->
stack
[
vm
->
sp
++
]
=
vm
->
jit_resume
.
vstack
[
i
];
int
resume_off
=
(
int
)
vm
->
jit_resume
.
ip_offset
;
uint8_t
*
scan
=
func
->
code
;
uint8_t
*
scan_end
=
func
->
code
+
resume_off
;
typedef
struct
{
uint8_t
*
catch_ip
;
int
saved_sp
;
}
pending_h
;
pending_h
h_stack
[
SV_TRY_MAX
];
int
enclosing_count
=
0
;
int
total_depth
=
0
;
bool
is_enclosing
[
SV_TRY_MAX
];
while
(
scan
<
scan_end
)
{
sv_op_t
scan_op
=
(
sv_op_t
)
*
scan
;
int
scan_sz
=
sv_op_size
[
scan_op
];
if
(
scan_sz
==
0
)
break
;
if
(
scan_op
==
OP_TRY_PUSH
&&
total_depth
<
SV_TRY_MAX
)
{
int32_t
off
=
sv_get_i32
(
scan
+
1
);
int
catch_off
=
(
int
)(
scan
-
func
->
code
)
+
scan_sz
+
off
;
is_enclosing
[
total_depth
]
=
(
catch_off
>
resume_off
);
if
(
is_enclosing
[
total_depth
])
{
h_stack
[
enclosing_count
].
catch_ip
=
func
->
code
+
catch_off
;
h_stack
[
enclosing_count
].
saved_sp
=
vm
->
sp
;
enclosing_count
++
;
}
total_depth
++
;
}
else
if
(
scan_op
==
OP_TRY_POP
&&
total_depth
>
0
)
{
total_depth
--
;
if
(
is_enclosing
[
total_depth
])
enclosing_count
--
;
}
scan
+=
scan_sz
;
}
for
(
int
i
=
0
;
i
<
enclosing_count
;
i
++
)
{
if
(
vm
->
handler_depth
<
SV_HANDLER_MAX
)
{
sv_handler_t
*
h
=
&
vm
->
handler_stack
[
vm
->
handler_depth
++
];
h
->
kind
=
SV_HANDLER_TRY
;
h
->
ip
=
h_stack
[
i
].
catch_ip
;
h
->
saved_sp
=
h_stack
[
i
].
saved_sp
;
frame
->
handler_top
=
vm
->
handler_depth
;
}
}
vm
->
jit_resume
.
active
=
false
;
}
#endif
static
const
void
*
dispatch
[
OP__COUNT
]
=
{
#define OP_DEF(name, size, n_pop, n_push, f) [OP_##name] = &&L_##name,
#include
"silver/opcode.h"
};
ant_value_t
sv_err
;
#define VM_CHECK(expr) do { \
frame->ip = ip; \
sv_err = (expr); \
if (is_err(sv_err)) goto sv_throw; \
} while (0)
ant_value_t
tc_this
=
js_mkundef
();
#define DISPATCH() goto *dispatch[*ip]
#define NEXT(n) do { ip += (n); DISPATCH(); } while (0)
#ifdef ANT_JIT
#define JIT_OSR_BACK_EDGE() do { \
if (!func->jit_compile_failed) { \
if (!func->type_feedback) sv_tfb_ensure(func); \
if (++func->back_edge_count >= SV_JIT_OSR_THRESHOLD) { \
ant_value_t osr_r = sv_jit_try_osr( \
vm, js, frame, func, \
(int)(ip - func->code)); \
if (osr_r != SV_JIT_RETRY_INTERP) { \
if (is_err(osr_r)) { sv_err = osr_r; goto sv_throw; } \
vm->sp = frame->prev_sp; \
if (vm->fp <= entry_fp) { \
vm_result = osr_r; \
goto sv_leave; \
} \
vm->fp--; \
frame = &vm->frames[vm->fp]; \
func = frame->func; \
bp = frame->bp; \
lp = frame->lp; \
ip = frame->ip; \
vm->stack[vm->sp++] = osr_r; \
DISPATCH(); \
} \
} \
} \
} while (0)
#else
#define JIT_OSR_BACK_EDGE() ((void)0)
#endif
DISPATCH
();
L_CONST
:
{
sv_op_const
(
vm
,
func
,
ip
);
NEXT
(
5
);
}
L_CONST_I8
:
{
sv_op_const_i8
(
vm
,
ip
);
NEXT
(
2
);
}
L_CONST8
:
{
sv_op_const8
(
vm
,
func
,
ip
);
NEXT
(
2
);
}
L_UNDEF
:
{
sv_op_undef
(
vm
);
NEXT
(
1
);
}
L_NULL
:
{
sv_op_null
(
vm
);
NEXT
(
1
);
}
L_TRUE
:
{
sv_op_true
(
vm
);
NEXT
(
1
);
}
L_FALSE
:
{
sv_op_false
(
vm
);
NEXT
(
1
);
}
L_THIS
:
{
sv_op_this
(
vm
,
frame
);
NEXT
(
1
);
}
L_GLOBAL
:
{
sv_op_global
(
vm
,
js
);
NEXT
(
1
);
}
L_OBJECT
:
{
sv_op_object
(
vm
,
js
,
func
,
ip
);
NEXT
(
1
);
}
L_ARRAY
:
{
sv_op_array
(
vm
,
js
,
ip
);
NEXT
(
3
);
}
L_REGEXP
:
{
sv_op_regexp
(
vm
,
js
);
NEXT
(
1
);
}
L_CLOSURE
:
{
sv_op_closure
(
vm
,
js
,
frame
,
func
,
ip
);
NEXT
(
5
);
}
L_POP
:
{
sv_op_pop
(
vm
);
NEXT
(
1
);
}
L_DUP
:
{
sv_op_dup
(
vm
);
NEXT
(
1
);
}
L_DUP2
:
{
sv_op_dup2
(
vm
);
NEXT
(
1
);
}
L_SWAP
:
{
sv_op_swap
(
vm
);
NEXT
(
1
);
}
L_ROT3L
:
{
sv_op_rot3l
(
vm
);
NEXT
(
1
);
}
L_ROT3R
:
{
sv_op_rot3r
(
vm
);
NEXT
(
1
);
}
L_NIP
:
{
sv_op_nip
(
vm
);
NEXT
(
1
);
}
L_NIP2
:
{
sv_op_nip2
(
vm
);
NEXT
(
1
);
}
L_INSERT2
:
{
sv_op_insert2
(
vm
);
NEXT
(
1
);
}
L_INSERT3
:
{
sv_op_insert3
(
vm
);
NEXT
(
1
);
}
L_SWAP_UNDER
:
{
sv_op_swap_under
(
vm
);
NEXT
(
1
);
}
L_ROT4_UNDER
:
{
sv_op_rot4_under
(
vm
);
NEXT
(
1
);
}
L_GET_LOCAL
:
{
sv_op_get_local
(
vm
,
lp
,
ip
);
NEXT
(
3
);
}
L_PUT_LOCAL
:
{
sv_op_put_local
(
vm
,
lp
,
func
,
ip
);
NEXT
(
3
);
}
L_SET_LOCAL
:
{
sv_op_set_local
(
vm
,
lp
,
func
,
ip
);
NEXT
(
3
);
}
L_GET_LOCAL8
:
{
sv_op_get_local8
(
vm
,
lp
,
ip
);
NEXT
(
2
);
}
L_PUT_LOCAL8
:
{
sv_op_put_local8
(
vm
,
lp
,
func
,
ip
);
NEXT
(
2
);
}
L_SET_LOCAL8
:
{
sv_op_set_local8
(
vm
,
lp
,
func
,
ip
);
NEXT
(
2
);
}
L_SET_LOCAL_UNDEF
:
{
sv_op_set_local_undef
(
lp
,
ip
);
NEXT
(
3
);
}
L_GET_LOCAL_CHK
:
{
VM_CHECK
(
sv_op_get_local_chk
(
vm
,
lp
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_PUT_LOCAL_CHK
:
{
VM_CHECK
(
sv_op_put_local_chk
(
vm
,
lp
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_GET_ARG
:
{
sv_op_get_arg
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_PUT_ARG
:
{
sv_op_put_arg
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_SET_ARG
:
{
sv_op_set_arg
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_REST
:
{
sv_op_rest
(
vm
,
frame
,
js
,
ip
);
NEXT
(
3
);
}
L_GET_UPVAL
:
{
VM_CHECK
(
sv_op_get_upval
(
vm
,
frame
,
js
,
ip
));
NEXT
(
3
);
}
L_PUT_UPVAL
:
{
sv_op_put_upval
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_SET_UPVAL
:
{
sv_op_set_upval
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_CLOSE_UPVAL
:
{
sv_op_close_upval
(
vm
,
frame
,
ip
);
NEXT
(
3
);
}
L_GET_GLOBAL
:
{
VM_CHECK
(
sv_op_get_global
(
vm
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_GET_GLOBAL_UNDEF
:
{
sv_op_get_global_undef
(
vm
,
js
,
func
,
ip
);
NEXT
(
7
);
}
L_PUT_GLOBAL
:
{
VM_CHECK
(
sv_op_put_global
(
vm
,
js
,
frame
,
func
,
ip
));
NEXT
(
5
);
}
L_GET_FIELD
:
{
VM_CHECK
(
sv_op_get_field
(
vm
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_GET_FIELD2
:
{
VM_CHECK
(
sv_op_get_field2
(
vm
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_PUT_FIELD
:
{
VM_CHECK
(
sv_op_put_field
(
vm
,
js
,
func
,
ip
));
NEXT
(
7
);
}
L_GET_ELEM
:
{
VM_CHECK
(
sv_op_get_elem
(
vm
,
js
,
func
,
ip
));
NEXT
(
1
);
}
L_GET_ELEM2
:
{
VM_CHECK
(
sv_op_get_elem2
(
vm
,
js
,
func
,
ip
));
NEXT
(
1
);
}
L_PUT_ELEM
:
{
VM_CHECK
(
sv_op_put_elem
(
vm
,
js
));
NEXT
(
1
);
}
L_DEFINE_FIELD
:
{
sv_op_define_field
(
vm
,
js
,
func
,
ip
);
NEXT
(
5
);
}
L_GET_LENGTH
:
{
VM_CHECK
(
sv_op_get_length
(
vm
,
js
));
NEXT
(
1
);
}
L_GET_FIELD_OPT
:
{
VM_CHECK
(
sv_op_get_field_opt
(
vm
,
js
,
func
,
ip
));
NEXT
(
5
);
}
L_GET_ELEM_OPT
:
{
VM_CHECK
(
sv_op_get_elem_opt
(
vm
,
js
,
func
,
ip
));
NEXT
(
1
);
}
L_GET_PRIVATE
:
{
sv_op_get_private
(
vm
,
js
);
NEXT
(
1
);
}
L_PUT_PRIVATE
:
{
sv_op_put_private
(
vm
,
js
);
NEXT
(
1
);
}
L_DEF_PRIVATE
:
{
sv_op_def_private
(
vm
,
js
);
NEXT
(
1
);
}
L_GET_SUPER
:
{
sv_op_get_super
(
vm
,
js
);
NEXT
(
1
);
}
L_GET_SUPER_VAL
:
{
sv_op_get_super_val
(
vm
,
js
);
NEXT
(
1
);
}
L_PUT_SUPER_VAL
:
{
sv_op_put_super_val
(
vm
,
js
);
NEXT
(
1
);
}
L_ADD
:
{
ant_value_t
r
=
vm
->
stack
[
vm
->
sp
-
1
],
l
=
vm
->
stack
[
vm
->
sp
-
2
];
sv_tfb_record2
(
func
,
ip
,
l
,
r
);
if
(
__builtin_expect
(
vtype
(
l
)
==
T_NUM
&&
vtype
(
r
)
==
T_NUM
,
1
))
{
vm
->
sp
--
;
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
+
tod
(
r
));
NEXT
(
1
);
}
VM_CHECK
(
sv_op_add
(
vm
,
js
));
NEXT
(
1
);
}
L_ADD_NUM
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
l
=
vm
->
stack
[
vm
->
sp
-
1
];
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
+
tod
(
r
));
NEXT
(
1
);
}
L_SUB
:
{
ant_value_t
r
=
vm
->
stack
[
vm
->
sp
-
1
],
l
=
vm
->
stack
[
vm
->
sp
-
2
];
sv_tfb_record2
(
func
,
ip
,
l
,
r
);
if
(
__builtin_expect
(
vtype
(
l
)
==
T_NUM
&&
vtype
(
r
)
==
T_NUM
,
1
))
{
vm
->
sp
--
;
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
-
tod
(
r
));
NEXT
(
1
);
}
VM_CHECK
(
sv_op_sub
(
vm
,
js
));
NEXT
(
1
);
}
L_SUB_NUM
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
l
=
vm
->
stack
[
vm
->
sp
-
1
];
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
-
tod
(
r
));
NEXT
(
1
);
}
L_MUL_NUM
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
l
=
vm
->
stack
[
vm
->
sp
-
1
];
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
*
tod
(
r
));
NEXT
(
1
);
}
L_DIV_NUM
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
l
=
vm
->
stack
[
vm
->
sp
-
1
];
vm
->
stack
[
vm
->
sp
-
1
]
=
tov
(
tod
(
l
)
/
tod
(
r
));
NEXT
(
1
);
}
L_MUL
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_mul
(
vm
,
js
));
NEXT
(
1
);
}
L_DIV
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_div
(
vm
,
js
));
NEXT
(
1
);
}
L_MOD
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_mod
(
vm
,
js
));
NEXT
(
1
);
}
L_NEG
:
{
sv_tfb_record1
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_neg
(
vm
,
js
));
NEXT
(
1
);
}
L_ADD_LOCAL
:
{
sv_tfb_record2
(
func
,
ip
,
lp
[
sv_get_u8
(
ip
+
1
)],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_add_local
(
vm
,
lp
,
js
,
func
,
ip
));
NEXT
(
2
);
}
L_EXP
:
{
VM_CHECK
(
sv_op_exp
(
vm
,
js
));
NEXT
(
1
);
}
L_UPLUS
:
{
VM_CHECK
(
sv_op_uplus
(
vm
,
js
));
NEXT
(
1
);
}
L_INC
:
{
sv_op_inc
(
vm
);
NEXT
(
1
);
}
L_DEC
:
{
sv_op_dec
(
vm
);
NEXT
(
1
);
}
L_POST_INC
:
{
sv_op_post_inc
(
vm
);
NEXT
(
1
);
}
L_POST_DEC
:
{
sv_op_post_dec
(
vm
);
NEXT
(
1
);
}
L_INC_LOCAL
:
{
sv_op_inc_local
(
vm
,
lp
,
func
,
ip
);
NEXT
(
2
);
}
L_DEC_LOCAL
:
{
sv_op_dec_local
(
vm
,
lp
,
func
,
ip
);
NEXT
(
2
);
}
L_EQ
:
{
sv_op_eq
(
vm
,
js
);
NEXT
(
1
);
}
L_NE
:
{
sv_op_ne
(
vm
,
js
);
NEXT
(
1
);
}
L_SEQ
:
{
sv_op_seq
(
vm
,
js
);
NEXT
(
1
);
}
L_SNE
:
{
sv_op_sne
(
vm
,
js
);
NEXT
(
1
);
}
L_LT
:
{
ant_value_t
r
=
vm
->
stack
[
vm
->
sp
-
1
],
l
=
vm
->
stack
[
vm
->
sp
-
2
];
sv_tfb_record2
(
func
,
ip
,
l
,
r
);
if
(
__builtin_expect
(
vtype
(
l
)
==
T_NUM
&&
vtype
(
r
)
==
T_NUM
,
1
))
{
vm
->
sp
--
;
vm
->
stack
[
vm
->
sp
-
1
]
=
mkval
(
T_BOOL
,
tod
(
l
)
<
tod
(
r
));
NEXT
(
1
);
}
VM_CHECK
(
sv_op_lt
(
vm
,
js
));
NEXT
(
1
);
}
L_LE
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_le
(
vm
,
js
));
NEXT
(
1
);
}
L_GT
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_gt
(
vm
,
js
));
NEXT
(
1
);
}
L_GE
:
{
sv_tfb_record2
(
func
,
ip
,
vm
->
stack
[
vm
->
sp
-2
],
vm
->
stack
[
vm
->
sp
-1
]);
VM_CHECK
(
sv_op_ge
(
vm
,
js
));
NEXT
(
1
);
}
L_INSTANCEOF
:
{
VM_CHECK
(
sv_op_instanceof
(
vm
,
js
,
func
,
ip
));
NEXT
(
3
);
}
L_IN
:
{
VM_CHECK
(
sv_op_in
(
vm
,
js
));
NEXT
(
1
);
}
L_IS_NULLISH
:
{
sv_op_is_nullish
(
vm
);
NEXT
(
1
);
}
L_IS_UNDEF_OR_NULL
:
{
sv_op_is_undef_or_null
(
vm
);
NEXT
(
1
);
}
L_BAND
:
{
VM_CHECK
(
sv_op_band
(
vm
,
js
));
NEXT
(
1
);
}
L_BOR
:
{
VM_CHECK
(
sv_op_bor
(
vm
,
js
));
NEXT
(
1
);
}
L_BXOR
:
{
VM_CHECK
(
sv_op_bxor
(
vm
,
js
));
NEXT
(
1
);
}
L_BNOT
:
{
VM_CHECK
(
sv_op_bnot
(
vm
,
js
));
NEXT
(
1
);
}
L_SHL
:
{
VM_CHECK
(
sv_op_shl
(
vm
,
js
));
NEXT
(
1
);
}
L_SHR
:
{
VM_CHECK
(
sv_op_shr
(
vm
,
js
));
NEXT
(
1
);
}
L_USHR
:
{
VM_CHECK
(
sv_op_ushr
(
vm
,
js
));
NEXT
(
1
);
}
L_NOT
:
{
sv_op_not
(
vm
,
js
);
NEXT
(
1
);
}
L_TYPEOF
:
{
sv_op_typeof
(
vm
,
js
);
NEXT
(
1
);
}
L_VOID
:
{
sv_op_void
(
vm
);
NEXT
(
1
);
}
L_DELETE
:
{
VM_CHECK
(
sv_op_delete
(
vm
,
js
));
NEXT
(
1
);
}
L_DELETE_VAR
:
{
sv_op_delete_var
(
vm
,
js
,
func
,
ip
);
NEXT
(
5
);
}
L_JMP
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp
(
ip
);
if
(
ip
<=
prev
)
{
gc_maybe
(
js
);
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_FALSE
:
{
uint8_t
*
prev
=
ip
;
ant_value_t
v
=
vm
->
stack
[
--
vm
->
sp
];
if
(
__builtin_expect
(
vtype
(
v
)
==
T_BOOL
,
1
))
{
ip
=
vdata
(
v
)
?
ip
+
sv_op_size
[
OP_JMP_FALSE
]
:
ip
+
sv_op_size
[
OP_JMP_FALSE
]
+
sv_get_i32
(
ip
+
1
);
}
else
{
ip
=
js_truthy
(
js
,
v
)
?
ip
+
sv_op_size
[
OP_JMP_FALSE
]
:
ip
+
sv_op_size
[
OP_JMP_FALSE
]
+
sv_get_i32
(
ip
+
1
);
}
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_TRUE
:
{
uint8_t
*
prev
=
ip
;
ant_value_t
v
=
vm
->
stack
[
--
vm
->
sp
];
if
(
__builtin_expect
(
vtype
(
v
)
==
T_BOOL
,
1
))
{
ip
=
vdata
(
v
)
?
ip
+
sv_op_size
[
OP_JMP_TRUE
]
+
sv_get_i32
(
ip
+
1
)
:
ip
+
sv_op_size
[
OP_JMP_TRUE
];
}
else
{
ip
=
js_truthy
(
js
,
v
)
?
ip
+
sv_op_size
[
OP_JMP_TRUE
]
+
sv_get_i32
(
ip
+
1
)
:
ip
+
sv_op_size
[
OP_JMP_TRUE
];
}
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_FALSE_PEEK
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp_false_peek
(
vm
,
js
,
ip
);
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_TRUE_PEEK
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp_true_peek
(
vm
,
js
,
ip
);
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_NOT_NULLISH
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp_not_nullish
(
vm
,
ip
);
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP8
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp8
(
ip
);
if
(
ip
<=
prev
)
{
js
->
prop_refs_len
=
0
;
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_FALSE8
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp_false8
(
vm
,
js
,
ip
);
if
(
ip
<=
prev
)
{
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
L_JMP_TRUE8
:
{
uint8_t
*
prev
=
ip
;
ip
=
sv_op_jmp_true8
(
vm
,
js
,
ip
);
if
(
ip
<=
prev
)
{
JIT_OSR_BACK_EDGE
();
}
DISPATCH
();
}
// TODO: make the methods below DRY
L_CALL
:
{
uint16_t
call_argc
=
sv_get_u16
(
ip
+
1
);
ant_value_t
*
call_args
=
&
vm
->
stack
[
vm
->
sp
-
call_argc
];
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
1
];
bool
is_super_call
=
(
vtype
(
frame
->
super_val
)
!=
T_UNDEF
&&
call_func
==
frame
->
super_val
);
ant_value_t
call_this
=
is_super_call
?
frame
->
this
:
js_mkundef
();
if
(
!
is_super_call
&&
vtype
(
frame
->
new_target
)
==
T_UNDEF
&&
vtype
(
call_func
)
==
T_FUNC
)
{
sv_closure_t
*
closure
=
js_func_closure
(
call_func
);
if
(
closure
->
func
!=
NULL
)
{
if
(
closure
->
call_flags
&
(
SV_CALL_HAS_BOUND_ARGS
|
SV_CALL_HAS_SUPER
))
goto
call_fallback
;
if
(
closure
->
func
->
is_async
)
goto
call_fallback
;
#ifdef ANT_JIT
{
sv_func_t
*
callee
=
closure
->
func
;
if
(
func
->
type_feedback
)
sv_tfb_record_call_target
(
func
,
(
int
)(
ip
-
func
->
code
),
callee
);
if
(
callee
->
jit_code
)
{
ant_value_t
jit_this
=
(
callee
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
?
closure
->
bound_this
:
js_mkundef
();
frame
->
ip
=
ip
+
3
;
sv_jit_enter
(
js
);
ant_value_t
jit_result
=
((
sv_jit_func_t
)
callee
->
jit_code
)(
vm
,
jit_this
,
call_args
,
(
int
)
call_argc
,
closure
);
sv_jit_leave
(
js
);
if
(
sv_is_jit_bailout
(
jit_result
))
{
sv_jit_on_bailout
(
callee
);
goto
call_fallback
;
}
vm
->
sp
-=
call_argc
+
1
;
if
(
is_err
(
jit_result
))
{
sv_err
=
jit_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
jit_result
;
ip
=
frame
->
ip
;
DISPATCH
();
}
if
(
!
callee
->
is_generator
)
{
uint32_t
cc
=
++
callee
->
call_count
;
if
(
__builtin_expect
(
cc
==
SV_TFB_ALLOC_THRESHOLD
,
0
))
sv_tfb_ensure
(
callee
);
if
(
cc
>
SV_JIT_THRESHOLD
)
{
sv_jit_func_t
jit_fn
=
sv_jit_compile
(
js
,
callee
,
closure
);
if
(
jit_fn
)
{
callee
->
jit_code
=
(
void
*
)
jit_fn
;
ant_value_t
jit_this
=
(
callee
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
?
closure
->
bound_this
:
js_mkundef
();
frame
->
ip
=
ip
+
3
;
sv_jit_enter
(
js
);
ant_value_t
jit_result
=
jit_fn
(
vm
,
jit_this
,
call_args
,
(
int
)
call_argc
,
closure
);
sv_jit_leave
(
js
);
if
(
sv_is_jit_bailout
(
jit_result
))
{
sv_jit_on_bailout
(
callee
);
goto
call_fallback
;
}
vm
->
sp
-=
call_argc
+
1
;
if
(
is_err
(
jit_result
))
{
sv_err
=
jit_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
jit_result
;
ip
=
frame
->
ip
;
DISPATCH
();
}
else
{
callee
->
call_count
=
0
;
callee
->
back_edge_count
=
0
;
}}
}
}
#endif
if
(
vm
->
fp
+
1
>=
vm
->
max_frames
&&
!
sv_vm_grow_frames
(
vm
))
{
sv_err
=
js_mkerr_typed
(
js
,
JS_ERR_RANGE
|
JS_ERR_NO_STACK
,
"Maximum AOT call stack size exceeded"
);
goto
sv_throw
;
}
if
(
closure
->
func
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
call_this
=
closure
->
bound_this
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
frame
->
ip
=
ip
+
3
;
vm
->
sp
-=
call_argc
+
1
;
vm
->
fp
++
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
closure
->
func
;
frame
->
func
=
func
;
frame
->
callee
=
call_func
;
frame
->
this
=
sv_normalize_this_for_frame
(
js
,
func
,
call_this
);
frame
->
new_target
=
js_mkundef
();
frame
->
super_val
=
js_mkundef
();
frame
->
prev_sp
=
vm
->
sp
;
frame
->
handler_base
=
vm
->
handler_depth
;
frame
->
handler_top
=
vm
->
handler_depth
;
frame
->
argc
=
call_argc
;
ant_value_t
*
call_bp
=
NULL
;
ant_value_t
*
call_lp
=
NULL
;
ant_value_t
call_stage_err
=
sv_stage_frame_args
(
vm
,
js
,
func
,
call_args
,
(
int
)
call_argc
,
&
call_bp
,
&
call_lp
);
if
(
is_err
(
call_stage_err
))
{
vm
->
fp
--
;
vm
->
sp
+=
call_argc
+
1
;
sv_err
=
call_stage_err
;
goto
sv_throw
;
}
frame
->
bp
=
call_bp
;
frame
->
lp
=
call_lp
;
frame
->
upvalues
=
closure
->
upvalues
;
frame
->
upvalue_count
=
closure
->
func
->
upvalue_count
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
func
->
code
;
DISPATCH
();
}
}
call_fallback
:;
frame
->
ip
=
ip
;
ant_value_t
call_result
=
sv_vm_call
(
vm
,
js
,
call_func
,
call_this
,
call_args
,
call_argc
,
NULL
,
false
);
vm
->
sp
-=
call_argc
+
1
;
if
(
is_err
(
call_result
))
{
sv_err
=
call_result
;
goto
sv_throw
;
}
if
(
is_super_call
&&
is_object_type
(
call_result
))
frame
->
this
=
call_result
;
vm
->
stack
[
vm
->
sp
++
]
=
call_result
;
NEXT
(
3
);
}
L_CALL_METHOD
:
{
uint16_t
call_argc
=
sv_get_u16
(
ip
+
1
);
ant_value_t
*
call_args
=
&
vm
->
stack
[
vm
->
sp
-
call_argc
];
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
1
];
ant_value_t
call_this
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
2
];
bool
is_super_call
=
(
vtype
(
frame
->
super_val
)
!=
T_UNDEF
&&
call_func
==
frame
->
super_val
);
if
(
!
is_super_call
&&
vtype
(
frame
->
new_target
)
==
T_UNDEF
&&
vtype
(
call_func
)
==
T_FUNC
)
{
sv_closure_t
*
closure
=
js_func_closure
(
call_func
);
if
(
closure
->
func
!=
NULL
)
{
if
(
closure
->
call_flags
&
(
SV_CALL_HAS_BOUND_ARGS
|
SV_CALL_HAS_SUPER
))
goto
call_method_fallback
;
if
(
closure
->
func
->
is_async
)
goto
call_method_fallback
;
#ifdef ANT_JIT
{
sv_func_t
*
callee
=
closure
->
func
;
if
(
callee
->
jit_code
)
{
ant_value_t
jit_this
=
(
callee
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
?
closure
->
bound_this
:
call_this
;
frame
->
ip
=
ip
+
3
;
sv_jit_enter
(
js
);
ant_value_t
jit_result
=
((
sv_jit_func_t
)
callee
->
jit_code
)(
vm
,
jit_this
,
call_args
,
(
int
)
call_argc
,
closure
);
sv_jit_leave
(
js
);
if
(
sv_is_jit_bailout
(
jit_result
))
{
sv_jit_on_bailout
(
callee
);
goto
call_method_fallback
;
}
vm
->
sp
-=
call_argc
+
2
;
if
(
is_err
(
jit_result
))
{
sv_err
=
jit_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
jit_result
;
ip
=
frame
->
ip
;
DISPATCH
();
}
if
(
!
callee
->
is_generator
)
{
uint32_t
cc
=
++
callee
->
call_count
;
if
(
__builtin_expect
(
cc
==
SV_TFB_ALLOC_THRESHOLD
,
0
))
sv_tfb_ensure
(
callee
);
if
(
cc
>
SV_JIT_THRESHOLD
)
{
sv_jit_func_t
jit_fn
=
sv_jit_compile
(
js
,
callee
,
closure
);
if
(
jit_fn
)
{
callee
->
jit_code
=
(
void
*
)
jit_fn
;
ant_value_t
jit_this
=
(
callee
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
?
closure
->
bound_this
:
call_this
;
frame
->
ip
=
ip
+
3
;
sv_jit_enter
(
js
);
ant_value_t
jit_result
=
jit_fn
(
vm
,
jit_this
,
call_args
,
(
int
)
call_argc
,
closure
);
sv_jit_leave
(
js
);
if
(
sv_is_jit_bailout
(
jit_result
))
{
sv_jit_on_bailout
(
callee
);
goto
call_method_fallback
;
}
vm
->
sp
-=
call_argc
+
2
;
if
(
is_err
(
jit_result
))
{
sv_err
=
jit_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
jit_result
;
ip
=
frame
->
ip
;
DISPATCH
();
}
else
{
callee
->
call_count
=
0
;
callee
->
back_edge_count
=
0
;
}}
}
}
#endif
if
(
vm
->
fp
+
1
>=
vm
->
max_frames
&&
!
sv_vm_grow_frames
(
vm
))
{
sv_err
=
js_mkerr_typed
(
js
,
JS_ERR_RANGE
|
JS_ERR_NO_STACK
,
"Maximum AOT call stack size exceeded"
);
goto
sv_throw
;
}
if
(
closure
->
func
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
call_this
=
closure
->
bound_this
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
frame
->
ip
=
ip
+
3
;
vm
->
sp
-=
call_argc
+
2
;
vm
->
fp
++
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
closure
->
func
;
frame
->
func
=
func
;
frame
->
callee
=
call_func
;
frame
->
this
=
sv_normalize_this_for_frame
(
js
,
func
,
call_this
);
frame
->
new_target
=
js_mkundef
();
frame
->
super_val
=
js_mkundef
();
frame
->
prev_sp
=
vm
->
sp
;
frame
->
handler_base
=
vm
->
handler_depth
;
frame
->
handler_top
=
vm
->
handler_depth
;
frame
->
argc
=
call_argc
;
ant_value_t
*
call_bp
=
NULL
;
ant_value_t
*
call_lp
=
NULL
;
ant_value_t
call_stage_err
=
sv_stage_frame_args
(
vm
,
js
,
func
,
call_args
,
(
int
)
call_argc
,
&
call_bp
,
&
call_lp
);
if
(
is_err
(
call_stage_err
))
{
vm
->
fp
--
;
vm
->
sp
+=
call_argc
+
2
;
sv_err
=
call_stage_err
;
goto
sv_throw
;
}
frame
->
bp
=
call_bp
;
frame
->
lp
=
call_lp
;
frame
->
upvalues
=
closure
->
upvalues
;
frame
->
upvalue_count
=
closure
->
func
->
upvalue_count
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
func
->
code
;
DISPATCH
();
}
}
call_method_fallback
:;
frame
->
ip
=
ip
;
if
(
is_super_call
)
js
->
new_target
=
frame
->
new_target
;
ant_value_t
call_result
=
sv_vm_call
(
vm
,
js
,
call_func
,
call_this
,
call_args
,
call_argc
,
NULL
,
is_super_call
);
vm
->
sp
-=
call_argc
+
2
;
if
(
is_err
(
call_result
))
{
sv_err
=
call_result
;
goto
sv_throw
;
}
if
(
is_super_call
&&
is_object_type
(
call_result
))
frame
->
this
=
call_result
;
vm
->
stack
[
vm
->
sp
++
]
=
call_result
;
NEXT
(
3
);
}
L_CALL_IS_PROTO
:
{
ant_value_t
call_arg
=
vm
->
stack
[
vm
->
sp
-
1
];
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
2
];
ant_value_t
call_this
=
vm
->
stack
[
vm
->
sp
-
3
];
ant_value_t
call_result
;
if
(
vtype
(
call_func
)
==
T_CFUNC
&&
js_as_cfunc
(
call_func
)
==
builtin_object_isPrototypeOf
)
{
call_result
=
sv_isproto_ic_eval
(
js
,
call_this
,
call_arg
,
func
,
ip
);
}
else
{
ant_value_t
call_args
[
1
]
=
{
call_arg
};
frame
->
ip
=
ip
;
call_result
=
sv_vm_call
(
vm
,
js
,
call_func
,
call_this
,
call_args
,
1
,
NULL
,
false
);
}
vm
->
sp
-=
3
;
if
(
is_err
(
call_result
))
{
sv_err
=
call_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
call_result
;
NEXT
(
3
);
}
L_TAIL_CALL
:
{
uint16_t
call_argc
=
sv_get_u16
(
ip
+
1
);
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
1
];
tc_this
=
js_mkundef
();
if
(
vm
->
handler_depth
==
frame
->
handler_base
&&
vtype
(
frame
->
new_target
)
==
T_UNDEF
&&
vtype
(
call_func
)
==
T_FUNC
)
{
sv_closure_t
*
closure
=
js_func_closure
(
call_func
);
if
(
closure
->
func
!=
NULL
)
{
if
(
!
closure
->
func
->
is_async
&&
!
(
closure
->
call_flags
&
(
SV_CALL_HAS_BOUND_ARGS
|
SV_CALL_HAS_SUPER
)))
{
if
(
closure
->
func
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
tc_this
=
closure
->
bound_this
;
goto
tail_call_inline
;
}
}
}
ant_value_t
*
call_args
=
&
vm
->
stack
[
vm
->
sp
-
call_argc
];
frame
->
ip
=
ip
;
ant_value_t
call_result
=
sv_vm_call
(
vm
,
js
,
call_func
,
tc_this
,
call_args
,
call_argc
,
NULL
,
false
);
vm
->
sp
-=
call_argc
+
1
;
if
(
is_err
(
call_result
))
{
sv_err
=
call_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
call_result
;
goto
L_RETURN
;
}
L_TAIL_CALL_METHOD
:
{
uint16_t
call_argc
=
sv_get_u16
(
ip
+
1
);
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
1
];
tc_this
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
2
];
if
(
vm
->
handler_depth
==
frame
->
handler_base
&&
vtype
(
frame
->
new_target
)
==
T_UNDEF
&&
vtype
(
call_func
)
==
T_FUNC
)
{
sv_closure_t
*
closure
=
js_func_closure
(
call_func
);
if
(
closure
->
func
!=
NULL
)
{
if
(
!
closure
->
func
->
is_async
&&
!
(
closure
->
call_flags
&
(
SV_CALL_HAS_BOUND_ARGS
|
SV_CALL_HAS_SUPER
)))
{
if
(
closure
->
func
->
is_arrow
||
vtype
(
closure
->
bound_this
)
!=
T_UNDEF
)
tc_this
=
closure
->
bound_this
;
goto
tail_call_inline
;
}
}
}
ant_value_t
*
call_args
=
&
vm
->
stack
[
vm
->
sp
-
call_argc
];
ant_value_t
call_result
=
sv_vm_call
(
vm
,
js
,
call_func
,
tc_this
,
call_args
,
call_argc
,
NULL
,
false
);
vm
->
sp
-=
call_argc
+
2
;
if
(
is_err
(
call_result
))
{
sv_err
=
call_result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
call_result
;
goto
L_RETURN
;
}
tail_call_inline
:
{
uint16_t
call_argc
=
sv_get_u16
(
ip
+
1
);
ant_value_t
*
call_args
=
&
vm
->
stack
[
vm
->
sp
-
call_argc
];
ant_value_t
call_func
=
vm
->
stack
[
vm
->
sp
-
call_argc
-
1
];
sv_closure_t
*
closure
=
js_func_closure
(
call_func
);
if
(
frame
->
bp
)
sv_close_upvalues_from_slot
(
vm
,
frame
->
bp
);
vm
->
sp
=
frame
->
prev_sp
;
int
arg_slots
=
(
(
int
)
call_argc
>
closure
->
func
->
param_count
)
?
(
int
)
call_argc
:
closure
->
func
->
param_count
;
int
need
=
arg_slots
+
closure
->
func
->
max_locals
;
ant_value_t
*
base
=
&
vm
->
stack
[
vm
->
sp
];
memmove
(
base
,
call_args
,
(
size_t
)
call_argc
*
sizeof
(
ant_value_t
));
for
(
int
i
=
(
int
)
call_argc
;
i
<
arg_slots
;
i
++
)
base
[
i
]
=
js_mkundef
();
ant_value_t
*
new_lp
=
base
+
arg_slots
;
for
(
int
i
=
0
;
i
<
closure
->
func
->
max_locals
;
i
++
)
new_lp
[
i
]
=
js_mkundef
();
vm
->
sp
=
frame
->
prev_sp
+
need
;
func
=
closure
->
func
;
frame
->
func
=
func
;
frame
->
callee
=
call_func
;
frame
->
this
=
sv_normalize_this_for_frame
(
js
,
func
,
tc_this
);
frame
->
new_target
=
js_mkundef
();
frame
->
super_val
=
js_mkundef
();
frame
->
argc
=
call_argc
;
frame
->
handler_base
=
vm
->
handler_depth
;
frame
->
handler_top
=
vm
->
handler_depth
;
frame
->
bp
=
base
;
frame
->
lp
=
new_lp
;
frame
->
upvalues
=
closure
->
upvalues
;
frame
->
upvalue_count
=
closure
->
func
->
upvalue_count
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
func
->
code
;
DISPATCH
();
}
L_NEW
:
{
VM_CHECK
(
sv_op_new
(
vm
,
js
,
ip
));
NEXT
(
3
);
}
L_APPLY
:
{
VM_CHECK
(
sv_op_apply
(
vm
,
js
,
ip
));
NEXT
(
3
);
}
L_EVAL
:
{
VM_CHECK
(
sv_op_eval
(
vm
,
js
,
frame
,
ip
));
NEXT
(
5
);
}
// TODO: make the methods below DRY
L_RETURN
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
if
(
__builtin_expect
(
vm
->
handler_depth
!=
frame
->
handler_base
,
0
))
{
uint8_t
*
finally_ip
=
sv_vm_unwind_for_return
(
vm
,
r
);
if
(
finally_ip
)
{
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
finally_ip
;
DISPATCH
();
}
vm
->
handler_depth
=
frame
->
handler_base
;
frame
->
handler_top
=
frame
->
handler_base
;
}
vm
->
sp
=
frame
->
prev_sp
;
if
(
vm
->
fp
<=
entry_fp
)
{
vm_result
=
r
;
goto
sv_leave
;
}
vm
->
fp
--
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
frame
->
ip
;
vm
->
stack
[
vm
->
sp
++
]
=
r
;
DISPATCH
();
}
L_RETURN_UNDEF
:
{
ant_value_t
r
=
js_mkundef
();
if
(
__builtin_expect
(
vm
->
handler_depth
!=
frame
->
handler_base
,
0
))
{
uint8_t
*
finally_ip
=
sv_vm_unwind_for_return
(
vm
,
r
);
if
(
finally_ip
)
{
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
finally_ip
;
DISPATCH
();
}
vm
->
handler_depth
=
frame
->
handler_base
;
frame
->
handler_top
=
frame
->
handler_base
;
}
vm
->
sp
=
frame
->
prev_sp
;
if
(
vm
->
fp
<=
entry_fp
)
{
vm_result
=
r
;
goto
sv_leave
;
}
vm
->
fp
--
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
frame
->
ip
;
vm
->
stack
[
vm
->
sp
++
]
=
r
;
DISPATCH
();
}
L_RETURN_ASYNC
:
{
ant_value_t
r
=
vm
->
stack
[
--
vm
->
sp
];
if
(
__builtin_expect
(
vm
->
handler_depth
!=
frame
->
handler_base
,
0
))
{
uint8_t
*
finally_ip
=
sv_vm_unwind_for_return
(
vm
,
r
);
if
(
finally_ip
)
{
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
finally_ip
;
DISPATCH
();
}
vm
->
handler_depth
=
frame
->
handler_base
;
frame
->
handler_top
=
frame
->
handler_base
;
}
vm
->
sp
=
frame
->
prev_sp
;
if
(
vm
->
fp
<=
entry_fp
)
{
vm_result
=
r
;
goto
sv_leave
;
}
vm
->
fp
--
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
frame
->
ip
;
vm
->
stack
[
vm
->
sp
++
]
=
r
;
DISPATCH
();
}
L_CHECK_CTOR
:
{
VM_CHECK
(
sv_op_check_ctor
(
vm
,
js
));
NEXT
(
1
);
}
L_CHECK_CTOR_RET
:
{
sv_op_check_ctor_ret
(
vm
,
frame
);
NEXT
(
1
);
}
L_HALT
:
{
vm_result
=
sv_op_halt
(
vm
,
frame
);
goto
sv_leave
;
}
L_THROW
:
{
sv_err
=
sv_op_throw
(
vm
);
goto
sv_throw
;
}
L_THROW_ERROR
:
{
sv_err
=
sv_op_throw_error
(
vm
,
js
,
func
,
ip
);
goto
sv_throw
;
}
L_TRY_PUSH
:
{
sv_op_try_push
(
vm
,
ip
);
NEXT
(
5
);
}
L_TRY_POP
:
{
sv_op_try_pop
(
vm
);
NEXT
(
1
);
}
L_CATCH
:
{
sv_op_catch
(
vm
,
sv_err
,
ip
);
NEXT
(
5
);
}
L_FINALLY
:
{
VM_CHECK
(
sv_op_finally
(
vm
,
js
,
ip
));
NEXT
(
5
);
}
L_FINALLY_RET
:
{
uint8_t
*
resume_ip
=
NULL
;
ant_value_t
completion
=
js_mkundef
();
sv_finally_ret_t
action
=
sv_op_finally_ret
(
vm
,
js
,
&
resume_ip
,
&
completion
);
if
(
action
==
SV_FINALLY_RET_ERROR
||
action
==
SV_FINALLY_RET_THROW
)
{
sv_err
=
completion
;
goto
sv_throw
;
}
if
(
action
==
SV_FINALLY_RET_RETURN
)
{
vm
->
handler_depth
=
frame
->
handler_base
;
frame
->
handler_top
=
frame
->
handler_base
;
vm
->
sp
=
frame
->
prev_sp
;
if
(
vm
->
fp
<=
entry_fp
)
{
vm_result
=
completion
;
goto
sv_leave
;
}
vm
->
fp
--
;
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
frame
->
ip
;
vm
->
stack
[
vm
->
sp
++
]
=
completion
;
DISPATCH
();
}
ip
=
resume_ip
;
DISPATCH
();
}
L_NIP_CATCH
:
{
sv_op_nip_catch
(
vm
);
NEXT
(
1
);
}
L_FOR_IN
:
{
VM_CHECK
(
sv_op_for_in
(
vm
,
js
));
NEXT
(
1
);
}
L_FOR_OF
:
{
VM_CHECK
(
sv_op_for_of
(
vm
,
js
));
NEXT
(
1
);
}
L_FOR_AWAIT_OF
:
{
VM_CHECK
(
sv_op_for_await_of
(
vm
,
js
));
NEXT
(
1
);
}
L_ITER_NEXT
:
{
VM_CHECK
(
sv_op_iter_next
(
vm
,
js
,
ip
));
NEXT
(
2
);
}
L_ITER_GET_VALUE
:
{
sv_op_iter_get_value
(
vm
,
js
);
NEXT
(
1
);
}
L_ITER_CLOSE
:
{
sv_op_iter_close
(
vm
,
js
);
NEXT
(
1
);
}
L_ITER_CALL
:
{
VM_CHECK
(
sv_op_iter_call
(
vm
,
js
,
ip
));
NEXT
(
2
);
}
L_AWAIT_ITER_NEXT
:
{
VM_CHECK
(
sv_op_await_iter_next
(
vm
,
js
));
NEXT
(
1
);
}
L_DESTRUCTURE_INIT
:
{
VM_CHECK
(
sv_op_destructure_init
(
vm
,
js
));
NEXT
(
1
);
}
L_DESTRUCTURE_NEXT
:
{
VM_CHECK
(
sv_op_destructure_next
(
vm
,
js
));
NEXT
(
1
);
}
L_DESTRUCTURE_REST
:
{
VM_CHECK
(
sv_op_destructure_rest
(
vm
,
js
));
NEXT
(
1
);
}
L_DESTRUCTURE_CLOSE
:{
sv_op_destructure_close
(
vm
,
js
);
NEXT
(
1
);
}
L_AWAIT
:
{
ant_value_t
await_val
=
vm
->
stack
[
--
vm
->
sp
];
ant_value_t
result
=
sv_await_value
(
js
,
await_val
);
if
(
is_err
(
result
))
{
sv_err
=
result
;
goto
sv_throw
;
}
vm
->
stack
[
vm
->
sp
++
]
=
result
;
NEXT
(
1
);
}
// TODO: implement
L_YIELD
:
{
NEXT
(
1
);
}
L_YIELD_STAR
:
{
NEXT
(
1
);
}
L_INITIAL_YIELD
:
{
NEXT
(
1
);
}
L_SPREAD
:
{
VM_CHECK
(
sv_op_spread
(
vm
,
js
));
NEXT
(
1
);
}
L_DEFINE_METHOD
:
{
sv_op_define_method
(
vm
,
js
,
func
,
ip
);
NEXT
(
6
);
}
L_DEFINE_METHOD_COMP
:
{
sv_op_define_method_comp
(
vm
,
js
,
ip
);
NEXT
(
2
);
}
L_SET_NAME
:
{
sv_op_set_name
(
vm
,
js
,
func
,
ip
);
NEXT
(
5
);
}
L_SET_NAME_COMP
:
{
sv_op_set_name_comp
(
vm
,
js
);
NEXT
(
1
);
}
L_SET_PROTO
:
{
sv_op_set_proto
(
vm
,
js
);
NEXT
(
1
);
}
L_SET_HOME_OBJ
:
{
sv_op_set_home_obj
(
vm
,
js
);
NEXT
(
1
);
}
L_APPEND
:
{
sv_op_append
(
vm
,
js
);
NEXT
(
1
);
}
L_COPY_DATA_PROPS
:
{
sv_op_copy_data_props
(
vm
,
js
,
ip
);
NEXT
(
2
);
}
L_DEFINE_CLASS
:
{
sv_op_define_class
(
vm
,
js
,
func
,
ip
);
NEXT
(
6
);
}
L_DEFINE_CLASS_COMP
:
{
sv_op_define_class_comp
(
vm
,
js
,
func
,
ip
);
NEXT
(
6
);
}
L_ADD_BRAND
:
{
sv_op_add_brand
(
vm
);
NEXT
(
1
);
}
L_TO_OBJECT
:
{
VM_CHECK
(
sv_op_to_object
(
vm
,
js
));
NEXT
(
1
);
}
L_TO_PROPKEY
:
{
sv_op_to_propkey
(
vm
,
js
);
NEXT
(
1
);
}
L_IS_UNDEF
:
{
sv_op_is_undef
(
vm
);
NEXT
(
1
);
}
L_IS_NULL
:
{
sv_op_is_null
(
vm
);
NEXT
(
1
);
}
L_IMPORT
:
{
VM_CHECK
(
sv_op_import
(
vm
,
js
));
NEXT
(
1
);
}
L_IMPORT_SYNC
:
{
VM_CHECK
(
sv_op_import_sync
(
vm
,
js
));
NEXT
(
1
);
}
L_IMPORT_DEFAULT
:
{
sv_op_import_default
(
vm
,
js
);
NEXT
(
1
);
}
L_EXPORT
:
{
VM_CHECK
(
sv_op_export
(
vm
,
js
,
func
,
ip
));
NEXT
(
5
);
}
L_EXPORT_ALL
:
{
VM_CHECK
(
sv_op_export_all
(
vm
,
js
));
NEXT
(
1
);
}
L_ENTER_WITH
:
{
VM_CHECK
(
sv_op_enter_with
(
vm
,
js
,
frame
));
NEXT
(
1
);
}
L_EXIT_WITH
:
{
sv_op_exit_with
(
vm
,
frame
);
NEXT
(
1
);
}
L_WITH_GET_VAR
:
{
VM_CHECK
(
sv_op_with_get_var
(
vm
,
js
,
frame
,
func
,
ip
));
NEXT
(
8
);
}
L_WITH_PUT_VAR
:
{
sv_op_with_put_var
(
vm
,
js
,
frame
,
func
,
ip
);
NEXT
(
8
);
}
L_WITH_DEL_VAR
:
{
sv_op_with_del_var
(
vm
,
js
,
frame
,
func
,
ip
);
NEXT
(
5
);
}
L_SPECIAL_OBJ
:
{
sv_op_special_obj
(
vm
,
js
,
frame
,
ip
);
NEXT
(
2
);
}
L_EMPTY
:
{
vm
->
stack
[
vm
->
sp
++
]
=
T_EMPTY
;
NEXT
(
1
);
}
L_PUT_CONST
:
{
func
->
constants
[
sv_get_u32
(
ip
+
1
)]
=
vm
->
stack
[
--
vm
->
sp
];
NEXT
(
5
);
}
L_DEBUGGER
:
{
NEXT
(
1
);
}
L_NOP
:
{
NEXT
(
1
);
}
L_LABEL
:
L_LINE_NUM
:
L_COL_NUM
:
L_INVALID
:
sv_err
=
js_mkerr
(
js
,
"invalid opcode %d"
,
(
int
)
*
ip
);
goto
sv_throw
;
sv_throw
:
{
uint8_t
*
catch_ip
=
sv_vm_throw
(
vm
,
sv_err
,
entry_fp
);
if
(
catch_ip
)
{
frame
=
&
vm
->
frames
[
vm
->
fp
];
func
=
frame
->
func
;
bp
=
frame
->
bp
;
lp
=
frame
->
lp
;
ip
=
catch_ip
;
DISPATCH
();
}
if
(
!
is_err
(
sv_err
))
{
vm_result
=
js_throw
(
js
,
sv_err
);
goto
sv_leave
;
}
vm_result
=
sv_err
;
goto
sv_leave
;
}
sv_leave
:
for
(
int
f
=
vm
->
fp
;
f
>=
entry_fp
;
f
--
)
{
ant_value_t
*
drop_bp
=
vm
->
frames
[
f
].
bp
;
if
(
drop_bp
)
sv_close_upvalues_from_slot
(
vm
,
drop_bp
);
}
vm
->
fp
=
entry_fp
;
vm
->
sp
=
vm
->
frames
[
entry_fp
].
prev_sp
;
vm
->
handler_depth
=
vm
->
frames
[
entry_fp
].
handler_base
;
return
vm_result
;
#undef DISPATCH
#undef NEXT
#undef VM_CHECK
// TODO: use entry_bp/frame->bp
// and sv_op_size values
(
void
)
bp
;
(
void
)
sv_op_size
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, May 3, 7:24 AM (10 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
538892
Default Alt Text
engine.c (46 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment