mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
pref,cgen: support -no-bounds-checking
, instead of -d no_bounds_checking
, and make it enable direct_array_access for all fns/methods.
This commit is contained in:
parent
54b623743d
commit
9edb48571f
@ -219,7 +219,7 @@ pub fn (a array) repeat_to_depth(count int, depth int) array {
|
||||
// c.insert(0, [1, 2]) // c now is [[1, 2], [3, 4]]
|
||||
// ```
|
||||
pub fn (mut a array) insert(i int, val voidptr) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i > a.len {
|
||||
panic('array.insert: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
@ -238,7 +238,7 @@ pub fn (mut a array) insert(i int, val voidptr) {
|
||||
// into an the array beginning at `i`.
|
||||
[unsafe]
|
||||
fn (mut a array) insert_many(i int, val voidptr, size int) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i > a.len {
|
||||
panic('array.insert_many: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
@ -297,7 +297,7 @@ pub fn (mut a array) delete(i int) {
|
||||
// dump(b) // b: [1, 2, 3, 4, 5, 6, 7, 8, 9] // `b` is still the same
|
||||
// ```
|
||||
pub fn (mut a array) delete_many(i int, size int) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i + size > a.len {
|
||||
endidx := if size > 1 { '..${i + size}' } else { '' }
|
||||
panic('array.delete: index out of range (i == $i$endidx, a.len == $a.len)')
|
||||
@ -379,7 +379,7 @@ fn (a array) get_unsafe(i int) voidptr {
|
||||
|
||||
// Private function. Used to implement array[] operator.
|
||||
fn (a array) get(i int) voidptr {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i >= a.len {
|
||||
panic('array.get: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
@ -404,7 +404,7 @@ fn (a array) get_with_check(i int) voidptr {
|
||||
// However, `a[0]` returns an error object
|
||||
// so it can be handled with an `or` block.
|
||||
pub fn (a array) first() voidptr {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if a.len == 0 {
|
||||
panic('array.first: array is empty')
|
||||
}
|
||||
@ -415,7 +415,7 @@ pub fn (a array) first() voidptr {
|
||||
// last returns the last element of the `array`.
|
||||
// If the `array` is empty, this will panic.
|
||||
pub fn (a array) last() voidptr {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if a.len == 0 {
|
||||
panic('array.last: array is empty')
|
||||
}
|
||||
@ -442,7 +442,7 @@ pub fn (a array) last() voidptr {
|
||||
// ```
|
||||
pub fn (mut a array) pop() voidptr {
|
||||
// in a sense, this is the opposite of `a << x`
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if a.len == 0 {
|
||||
panic('array.pop: array is empty')
|
||||
}
|
||||
@ -461,7 +461,7 @@ pub fn (mut a array) pop() voidptr {
|
||||
// See also: [trim](#array.trim)
|
||||
pub fn (mut a array) delete_last() {
|
||||
// copy pasting code for performance
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if a.len == 0 {
|
||||
panic('array.pop: array is empty')
|
||||
}
|
||||
@ -480,7 +480,7 @@ pub fn (mut a array) delete_last() {
|
||||
// Alternative: `.slice_ni()` will always return an array.
|
||||
fn (a array) slice(start int, _end int) array {
|
||||
mut end := _end
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if start > end {
|
||||
panic('array.slice: invalid slice index ($start > $end)')
|
||||
}
|
||||
@ -616,7 +616,7 @@ fn (mut a array) set_unsafe(i int, val voidptr) {
|
||||
|
||||
// Private function. Used to implement assignment to the array element.
|
||||
fn (mut a array) set(i int, val voidptr) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i >= a.len {
|
||||
panic('array.set: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ fn (a array) repeat_to_depth_noscan(count int, depth int) array {
|
||||
|
||||
// insert inserts a value in the array at index `i`
|
||||
fn (mut a array) insert_noscan(i int, val voidptr) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i > a.len {
|
||||
panic('array.insert: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
@ -138,7 +138,7 @@ fn (mut a array) insert_noscan(i int, val voidptr) {
|
||||
// insert_many inserts many values into the array from index `i`.
|
||||
[unsafe]
|
||||
fn (mut a array) insert_many_noscan(i int, val voidptr, size int) {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i > a.len {
|
||||
panic('array.insert_many: index out of range (i == $i, a.len == $a.len)')
|
||||
}
|
||||
@ -167,7 +167,7 @@ fn (mut a array) prepend_many_noscan(val voidptr, size int) {
|
||||
// pop returns the last element of the array, and removes it.
|
||||
fn (mut a array) pop_noscan() voidptr {
|
||||
// in a sense, this is the opposite of `a << x`
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if a.len == 0 {
|
||||
panic('array.pop: array is empty')
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ pub fn memdup_uncollectable(src voidptr, sz int) voidptr {
|
||||
|
||||
[inline]
|
||||
fn v_fixed_index(i int, len int) int {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if i < 0 || i >= len {
|
||||
s := 'fixed array index out of range (index: $i, len: $len)'
|
||||
panic(s)
|
||||
|
@ -499,7 +499,7 @@ pub fn (s string) replace_each(vals []string) string {
|
||||
// Example: assert '\tHello!'.replace_char(`\t`,` `,8) == ' Hello!'
|
||||
[direct_array_access]
|
||||
pub fn (s string) replace_char(rep u8, with u8, repeat int) string {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if repeat <= 0 {
|
||||
panic('string.replace_char(): tab length too short')
|
||||
}
|
||||
@ -873,7 +873,7 @@ fn (s string) substr2(start int, _end int, end_max bool) string {
|
||||
// Example: assert 'ABCD'.substr(1,3) == 'BC'
|
||||
[direct_array_access]
|
||||
pub fn (s string) substr(start int, end int) string {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if start > end || start > s.len || end > s.len || start < 0 || end < 0 {
|
||||
panic('substr($start, $end) out of bounds (len=$s.len)')
|
||||
}
|
||||
@ -1582,7 +1582,7 @@ pub fn (s string) str() string {
|
||||
// at returns the byte at index `idx`.
|
||||
// Example: assert 'ABC'.at(1) == u8(`B`)
|
||||
fn (s string) at(idx int) byte {
|
||||
$if !no_bounds_checking ? {
|
||||
$if !no_bounds_checking {
|
||||
if idx < 0 || idx >= s.len {
|
||||
panic('string index out of range: $idx / $s.len')
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ mut:
|
||||
tmp_count_declarations int // counter for unique tmp names (_d1, _d2 etc); does NOT reset, used for C declarations
|
||||
global_tmp_count int // like tmp_count but global and not resetted in each function
|
||||
discard_or_result bool // do not safe last ExprStmt of `or` block in tmp variable to defer ongoing expr usage
|
||||
is_direct_array_access bool // inside a `[direct_array_access fn a() {}` function
|
||||
is_assign_lhs bool // inside left part of assign expr (for array_set(), etc)
|
||||
is_void_expr_stmt bool // ExprStmt whos result is discarded
|
||||
is_arraymap_set bool // map or array set value state
|
||||
|
@ -57,6 +57,11 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.out_fn_start_pos << g.out.len
|
||||
}
|
||||
}
|
||||
prev_is_direct_array_access := g.is_direct_array_access
|
||||
g.is_direct_array_access = node.is_direct_arr || g.pref.no_bounds_checking
|
||||
defer {
|
||||
g.is_direct_array_access = prev_is_direct_array_access
|
||||
}
|
||||
g.gen_attrs(node.attrs)
|
||||
mut skip := false
|
||||
pos := g.out.len
|
||||
|
@ -18,29 +18,28 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
} else if sym.kind == .map {
|
||||
g.index_of_map(node, sym)
|
||||
} else if sym.kind == .string && !node.left_type.is_ptr() {
|
||||
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|
||||
|| node.is_direct
|
||||
if is_direct_array_access {
|
||||
gen_or := node.or_expr.kind != .absent || node.is_option
|
||||
if gen_or {
|
||||
tmp_opt := g.new_tmp_var()
|
||||
cur_line := g.go_before_stmt(0)
|
||||
g.out.write_string(util.tabs(g.indent))
|
||||
opt_elem_type := g.typ(ast.u8_type.set_flag(.optional))
|
||||
g.write('$opt_elem_type $tmp_opt = string_at_with_check(')
|
||||
g.expr(node.left)
|
||||
g.write('.str[ ')
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
g.write(']')
|
||||
g.writeln(');')
|
||||
if !node.is_option {
|
||||
g.or_block(tmp_opt, node.or_expr, ast.u8_type)
|
||||
}
|
||||
g.write('\n$cur_line*(byte*)&${tmp_opt}.data')
|
||||
} else {
|
||||
gen_or := node.or_expr.kind != .absent || node.is_option
|
||||
if gen_or {
|
||||
tmp_opt := g.new_tmp_var()
|
||||
cur_line := g.go_before_stmt(0)
|
||||
g.out.write_string(util.tabs(g.indent))
|
||||
opt_elem_type := g.typ(ast.u8_type.set_flag(.optional))
|
||||
g.write('$opt_elem_type $tmp_opt = string_at_with_check(')
|
||||
is_direct_array_access := g.is_direct_array_access || node.is_direct
|
||||
if is_direct_array_access {
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.write('.str[ ')
|
||||
g.expr(node.index)
|
||||
g.writeln(');')
|
||||
if !node.is_option {
|
||||
g.or_block(tmp_opt, node.or_expr, ast.u8_type)
|
||||
}
|
||||
g.write('\n$cur_line*(byte*)&${tmp_opt}.data')
|
||||
g.write(']')
|
||||
} else {
|
||||
g.write('string_at(')
|
||||
g.expr(node.left)
|
||||
@ -175,8 +174,7 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) {
|
||||
// `vals[i].field = x` is an exception and requires `array_get`:
|
||||
// `(*(Val*)array_get(vals, i)).field = x;`
|
||||
if g.is_assign_lhs && node.is_setter {
|
||||
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|
||||
|| node.is_direct
|
||||
is_direct_array_access := g.is_direct_array_access || node.is_direct
|
||||
is_op_assign := g.assign_op != .assign && info.elem_type != ast.string_type
|
||||
if is_direct_array_access {
|
||||
g.write('(($elem_type_str*)')
|
||||
@ -235,11 +233,11 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
is_direct_array_access := (unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr)
|
||||
|| node.is_direct
|
||||
is_direct_array_access := g.is_direct_array_access || node.is_direct
|
||||
// do not clone inside `opt_ok(opt_ok(&(string[]) {..})` before returns
|
||||
needs_clone := info.elem_type == ast.string_type_idx && g.is_autofree && !(g.inside_return
|
||||
&& g.fn_decl.return_type.has_flag(.optional)) && !g.is_assign_lhs
|
||||
&& g.fn_decl != unsafe { nil } && g.fn_decl.return_type.has_flag(.optional))
|
||||
&& !g.is_assign_lhs
|
||||
is_gen_or_and_assign_rhs := gen_or && !g.discard_or_result
|
||||
cur_line := if is_gen_or_and_assign_rhs {
|
||||
line := g.go_before_stmt(0)
|
||||
@ -353,8 +351,7 @@ fn (mut g Gen) index_of_fixed_array(node ast.IndexExpr, sym ast.TypeSymbol) {
|
||||
}
|
||||
}
|
||||
g.write('[')
|
||||
direct := unsafe { g.fn_decl != 0 } && g.fn_decl.is_direct_arr
|
||||
if (direct || node.index is ast.IntegerLiteral) || g.pref.translated {
|
||||
if g.is_direct_array_access || g.pref.translated || node.index is ast.IntegerLiteral {
|
||||
g.expr(node.index)
|
||||
} else {
|
||||
// bounds check
|
||||
|
@ -160,6 +160,7 @@ pub mut:
|
||||
ccompiler_type CompilerType // the type of the C compiler used
|
||||
third_party_option string
|
||||
building_v bool
|
||||
no_bounds_checking bool // `-no-bounds-checking` turns off *all* bounds checks for all functions at runtime, as if they all had been tagged with `[direct_array_access]`
|
||||
autofree bool // `v -manualfree` => false, `v -autofree` => true; false by default for now.
|
||||
// Disabling `free()` insertion results in better performance in some applications (e.g. compilers)
|
||||
trace_calls bool // -trace-calls true = the transformer stage will generate and inject print calls for tracing function calls
|
||||
@ -468,6 +469,12 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||
res.is_glibc = true
|
||||
res.build_options << arg
|
||||
}
|
||||
'-no-bounds-checking' {
|
||||
res.no_bounds_checking = true
|
||||
res.compile_defines << 'no_bounds_checking'
|
||||
res.compile_defines_all << 'no_bounds_checking'
|
||||
res.build_options << arg
|
||||
}
|
||||
'-no-builtin' {
|
||||
res.no_builtin = true
|
||||
res.build_options << arg
|
||||
@ -1016,6 +1023,9 @@ fn (mut prefs Preferences) parse_define(define string) {
|
||||
if define_parts.len == 1 {
|
||||
prefs.compile_defines << define
|
||||
prefs.compile_defines_all << define
|
||||
if define == 'no_bounds_checking' {
|
||||
prefs.no_bounds_checking = true
|
||||
}
|
||||
return
|
||||
}
|
||||
if define_parts.len == 2 {
|
||||
@ -1040,6 +1050,9 @@ fn (mut prefs Preferences) parse_define(define string) {
|
||||
|
||||
fn (mut prefs Preferences) diagnose_deprecated_defines(define_parts []string) {
|
||||
if define_parts[0] == 'force_embed_file' {
|
||||
eprintln('-d force_embed_file was deprecated in 2022/06/01. Now \$embed_file(file) always embeds the file, unless you pass `-d embed_only_metadata`.')
|
||||
eprintln('`-d force_embed_file` was deprecated in 2022/06/01. Now \$embed_file(file) always embeds the file, unless you pass `-d embed_only_metadata`.')
|
||||
}
|
||||
if define_parts[0] == 'no_bounds_checking' {
|
||||
eprintln('`-d no_bounds_checking` was deprecated in 2022/10/30. Use `-no-bounds-checking` instead.')
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user