1
1
//! Javascript object implementation.
2
2
3
- use std:: cell:: UnsafeCell ;
3
+ use std:: cell:: { Cell , UnsafeCell } ;
4
4
5
5
use crate :: {
6
6
gc:: { Gc , Trace } ,
@@ -11,6 +11,8 @@ use common::collections::HashMap;
11
11
mod function;
12
12
pub use function:: * ;
13
13
14
+ const ARRAY_BACKDOWN_PROCENT : f64 = 0.7 ;
15
+
14
16
bitflags:: bitflags! {
15
17
pub struct ObjectFlags : u8 {
16
18
const ERROR = 0b1 ;
@@ -26,6 +28,8 @@ pub struct Object {
26
28
array : UnsafeCell < Vec < Value > > ,
27
29
pub flags : ObjectFlags ,
28
30
pub function : Option < FunctionKind > ,
31
+ // TODO non null
32
+ map_backdown : Cell < Option < usize > > ,
29
33
}
30
34
31
35
impl Object {
@@ -35,6 +39,7 @@ impl Object {
35
39
prototype,
36
40
values : UnsafeCell :: new ( HashMap :: default ( ) ) ,
37
41
array : UnsafeCell :: new ( Vec :: new ( ) ) ,
42
+ map_backdown : Cell :: new ( None ) ,
38
43
flags,
39
44
function : None ,
40
45
}
@@ -72,16 +77,19 @@ impl Object {
72
77
if key. is_int ( ) {
73
78
let idx = key. cast_int ( ) ;
74
79
if idx >= 0 {
75
- return match ( * self . array . get ( ) ) . get ( idx as usize ) . copied ( ) {
76
- Some ( x) => Ok ( x) ,
77
- None => {
78
- if let Some ( proto) = self . prototype {
79
- proto. index ( key, realm)
80
- } else {
81
- Ok ( Value :: undefined ( ) )
80
+ let idx = idx as usize ;
81
+ if self . map_backdown . get ( ) . map ( |x| idx < x) . unwrap_or ( true ) {
82
+ return match ( * self . array . get ( ) ) . get ( idx) . copied ( ) {
83
+ Some ( x) => Ok ( x) ,
84
+ None => {
85
+ if let Some ( proto) = self . prototype {
86
+ proto. index ( key, realm)
87
+ } else {
88
+ Ok ( Value :: undefined ( ) )
89
+ }
82
90
}
83
- }
84
- } ;
91
+ } ;
92
+ }
85
93
}
86
94
}
87
95
let string = realm. to_string ( key) ?;
@@ -110,17 +118,38 @@ impl Object {
110
118
111
119
if key. is_int ( ) {
112
120
let idx = key. cast_int ( ) ;
113
- if idx >= 0 {
121
+ if idx >= 0
122
+ && self
123
+ . map_backdown
124
+ . get ( )
125
+ . map ( |x| ( idx as usize ) < x)
126
+ . unwrap_or ( true )
127
+ {
114
128
let idx = idx as usize ;
115
- if ( * self . array . get ( ) ) . len ( ) <= idx {
116
- ( * self . array . get ( ) ) . resize ( idx + 1 , Value :: undefined ( ) )
129
+ let len = ( * self . array . get ( ) ) . len ( ) ;
130
+ if len <= idx {
131
+ if ( idx - len) as f64 / len as f64 > ARRAY_BACKDOWN_PROCENT {
132
+ // Fill up to capacity since that part is already allocated any way.
133
+ let capacity = ( * self . array . get ( ) ) . capacity ( ) ;
134
+ ( * self . array . get ( ) ) . resize ( capacity, Value :: undefined ( ) ) ;
135
+ self . map_backdown . set ( Some ( capacity) ) ;
136
+ if idx < capacity {
137
+ ( * self . array . get ( ) ) [ idx] = value;
138
+ return Ok ( ( ) ) ;
139
+ }
140
+ } else {
141
+ ( * self . array . get ( ) ) . resize ( idx + 1 , Value :: undefined ( ) ) ;
142
+ ( * self . array . get ( ) ) [ idx] = value;
143
+ return Ok ( ( ) ) ;
144
+ }
145
+ } else {
146
+ ( * self . array . get ( ) ) [ idx] = value;
147
+ return Ok ( ( ) ) ;
117
148
}
118
- ( * self . array . get ( ) ) [ idx] = value
119
149
}
120
- } else {
121
- let string = realm. to_string ( key) ?;
122
- ( * self . values . get ( ) ) . insert ( string. to_string ( ) , value) ;
123
150
}
151
+ let string = realm. to_string ( key) ?;
152
+ ( * self . values . get ( ) ) . insert ( string. to_string ( ) , value) ;
124
153
Ok ( ( ) )
125
154
}
126
155
0 commit comments