67
67
final class NativeWasmMemory extends WasmMemory {
68
68
69
69
private long startAddress ;
70
+ /**
71
+ * The visible size of the Wasm linear memory.
72
+ */
70
73
private long size ;
74
+ /**
75
+ * The actual size of the memory buffer allocated by GraalWasm.
76
+ */
77
+ private long bufferSize ;
71
78
72
79
public static final long MAX_ALLOWED_SIZE = Sizes .MAX_MEMORY_64_INSTANCE_SIZE ;
73
80
74
81
private static final Unsafe unsafe ;
75
82
private static final VarHandle SIZE_FIELD ;
76
83
77
84
@ TruffleBoundary
78
- private NativeWasmMemory (long declaredMinSize , long declaredMaxSize , long initialSize , long maxAllowedSize , boolean indexType64 , boolean shared ) {
79
- super (declaredMinSize , declaredMaxSize , initialSize , maxAllowedSize , indexType64 , shared );
85
+ private NativeWasmMemory (long declaredMinSize , long declaredMaxSize , long initialSize , long maxAllowedSize , boolean indexType64 ) {
86
+ super (declaredMinSize , declaredMaxSize , initialSize , maxAllowedSize , indexType64 , false );
80
87
this .size = declaredMinSize ;
81
- final long byteSize = byteSize ();
82
- this .startAddress = allocate (byteSize );
88
+ final long initialBufferSize = byteSize ();
89
+ this .startAddress = allocate (initialBufferSize );
90
+ this .bufferSize = initialBufferSize ;
83
91
}
84
92
85
93
@ TruffleBoundary
86
- NativeWasmMemory (long declaredMinSize , long declaredMaxSize , boolean indexType64 , boolean shared ) {
87
- this (declaredMinSize , declaredMaxSize , declaredMinSize , WasmMath .minUnsigned (declaredMaxSize , MAX_ALLOWED_SIZE ), indexType64 , shared );
94
+ NativeWasmMemory (long declaredMinSize , long declaredMaxSize , boolean indexType64 ) {
95
+ this (declaredMinSize , declaredMaxSize , declaredMinSize , WasmMath .minUnsigned (declaredMaxSize , MAX_ALLOWED_SIZE ), indexType64 );
88
96
}
89
97
90
- private static long allocate (long byteSize ) {
98
+ private static long allocate (long newBufferSize ) {
91
99
try {
92
- final long address = unsafe .allocateMemory (byteSize );
93
- unsafe .setMemory (address , byteSize , (byte ) 0 );
100
+ final long address = unsafe .allocateMemory (newBufferSize );
101
+ unsafe .setMemory (address , newBufferSize , (byte ) 0 );
94
102
return address ;
95
103
} catch (OutOfMemoryError error ) {
96
104
throw WasmException .create (Failure .MEMORY_ALLOCATION_FAILED );
@@ -118,13 +126,26 @@ public synchronized long grow(long extraPageSize) {
118
126
// Condition above and limit on maxAllowedSize (see NativeWasmMemory#MAX_ALLOWED_SIZE)
119
127
// ensure computation of targetByteSize does not overflow.
120
128
final long targetByteSize = Math .multiplyExact (Math .addExact (previousSize , extraPageSize ), MEMORY_PAGE_SIZE );
121
- final long updatedSize = previousSize + extraPageSize ;
122
- try {
123
- startAddress = unsafe .reallocateMemory (startAddress , targetByteSize );
124
- unsafe .setMemory (startAddress + byteSize (), targetByteSize - byteSize (), (byte ) 0 );
125
- } catch (OutOfMemoryError error ) {
126
- throw WasmException .create (Failure .MEMORY_ALLOCATION_FAILED );
129
+ if (Long .compareUnsigned (targetByteSize , bufferSize ) > 0 ) {
130
+ try {
131
+ long newBufferSize = newBufferSize (targetByteSize );
132
+ startAddress = unsafe .reallocateMemory (startAddress , newBufferSize );
133
+ unsafe .setMemory (startAddress + bufferSize , newBufferSize - bufferSize , (byte ) 0 );
134
+ bufferSize = newBufferSize ;
135
+ } catch (OutOfMemoryError error ) {
136
+ // Over-allocating failed, so try to allocate at least the amount of memory that
137
+ // was requested.
138
+ try {
139
+ long newBufferSize = targetByteSize ;
140
+ startAddress = unsafe .reallocateMemory (startAddress , newBufferSize );
141
+ unsafe .setMemory (startAddress + bufferSize , newBufferSize - bufferSize , (byte ) 0 );
142
+ bufferSize = newBufferSize ;
143
+ } catch (OutOfMemoryError errorAgain ) {
144
+ throw WasmException .create (Failure .MEMORY_ALLOCATION_FAILED );
145
+ }
146
+ }
127
147
}
148
+ final long updatedSize = previousSize + extraPageSize ;
128
149
currentMinSize = updatedSize ;
129
150
SIZE_FIELD .setVolatile (this , updatedSize );
130
151
invokeGrowCallback ();
@@ -134,12 +155,21 @@ public synchronized long grow(long extraPageSize) {
134
155
}
135
156
}
136
157
158
+ public long newBufferSize (long targetByteSize ) {
159
+ // bufferSize <= Sizes.MAX_MEMORY_64_INSTANCE_BYTE_SIZE, so this should not overflow
160
+ long prefBufferSize = Math .addExact (bufferSize , bufferSize >> 1 );
161
+ // maxAllowedByteSize <= Sizes.MAX_MEMORY_64_INSTANCE_BYTE_SIZE, so no overflow
162
+ long maxAllowedByteSize = Math .multiplyExact (maxAllowedSize (), MEMORY_PAGE_SIZE );
163
+ return Math .max (targetByteSize , Math .min (prefBufferSize , maxAllowedByteSize ));
164
+ }
165
+
137
166
@ ExportMessage
138
167
@ TruffleBoundary
139
168
public void reset () {
140
169
free ();
141
170
size = declaredMinSize ;
142
- startAddress = allocate (byteSize ());
171
+ bufferSize = byteSize ();
172
+ startAddress = allocate (bufferSize );
143
173
currentMinSize = declaredMinSize ;
144
174
}
145
175
@@ -930,7 +960,7 @@ public int atomic_wait64(Node node, long address, long expected, long timeout) {
930
960
931
961
@ ExportMessage
932
962
public WasmMemory duplicate () {
933
- final NativeWasmMemory other = new NativeWasmMemory (declaredMinSize , declaredMaxSize , size , maxAllowedSize , indexType64 , shared );
963
+ final NativeWasmMemory other = new NativeWasmMemory (declaredMinSize , declaredMaxSize , size , maxAllowedSize , indexType64 );
934
964
unsafe .copyMemory (this .startAddress , other .startAddress , this .byteSize ());
935
965
return other ;
936
966
}
@@ -967,6 +997,7 @@ public boolean freed() {
967
997
@ TruffleBoundary
968
998
private void free () {
969
999
unsafe .freeMemory (startAddress );
1000
+ bufferSize = 0 ;
970
1001
startAddress = 0 ;
971
1002
size = 0 ;
972
1003
}
0 commit comments