45
45
46
46
import java .io .IOException ;
47
47
import java .nio .channels .FileChannel .MapMode ;
48
+ import java .nio .ByteBuffer ;
49
+ import java .nio .channels .ByteChannel ;
48
50
import java .nio .channels .SeekableByteChannel ;
49
51
import java .nio .file .StandardOpenOption ;
50
52
import java .util .HashSet ;
64
66
import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
65
67
import com .oracle .truffle .api .dsl .NodeFactory ;
66
68
import com .oracle .truffle .api .dsl .Specialization ;
69
+ import com .oracle .truffle .api .profiles .BranchProfile ;
67
70
import com .oracle .truffle .api .profiles .ValueProfile ;
68
71
69
72
@ CoreFunctions (defineModule = "mmap" )
@@ -90,15 +93,24 @@ public MMapModuleBuiltins() {
90
93
public abstract static class MMapNode extends PythonBuiltinNode {
91
94
92
95
private final ValueProfile classProfile = ValueProfile .createClassProfile ();
96
+ private final BranchProfile invalidLengthProfile = BranchProfile .create ();
93
97
94
- @ Specialization (guards = {"isNoValue(access)" , "isNoValue(offset)" })
98
+ @ Specialization (guards = {"fd < 0" , "isNoValue(access)" , "isNoValue(offset)" })
99
+ PMMap doAnonymous (LazyPythonClass clazz , int fd , int length , Object tagname , @ SuppressWarnings ("unused" ) PNone access , @ SuppressWarnings ("unused" ) PNone offset ) {
100
+ checkLength (length );
101
+ return new PMMap (clazz , new AnonymousMap (length ), length , 0 );
102
+ }
103
+
104
+ @ Specialization (guards = {"fd >= 0" , "isNoValue(access)" , "isNoValue(offset)" })
95
105
PMMap doIt (LazyPythonClass clazz , int fd , int length , Object tagname , @ SuppressWarnings ("unused" ) PNone access , @ SuppressWarnings ("unused" ) PNone offset ) {
96
- return doGeneric (clazz , fd , length , tagname , ACCESS_DEFAULT , 0 );
106
+ return doFile (clazz , fd , length , tagname , ACCESS_DEFAULT , 0 );
97
107
}
98
108
99
109
// mmap(fileno, length, tagname=None, access=ACCESS_DEFAULT[, offset])
100
- @ Specialization
101
- PMMap doGeneric (LazyPythonClass clazz , int fd , int length , @ SuppressWarnings ("unused" ) Object tagname , int access , long offset ) {
110
+ @ Specialization (guards = "fd >= 0" )
111
+ PMMap doFile (LazyPythonClass clazz , int fd , int length , @ SuppressWarnings ("unused" ) Object tagname , int access , long offset ) {
112
+ checkLength (length );
113
+
102
114
String path = getContext ().getResources ().getFilePath (fd );
103
115
TruffleFile truffleFile = getContext ().getEnv ().getTruffleFile (path );
104
116
@@ -133,5 +145,67 @@ private MapMode convertAccessToMapMode(int access) {
133
145
throw raise (ValueError , "mmap invalid access parameter." );
134
146
}
135
147
148
+ private void checkLength (int length ) {
149
+ if (length < 0 ) {
150
+ invalidLengthProfile .enter ();
151
+ throw raise (PythonBuiltinClassType .OverflowError , "memory mapped length must be positive" );
152
+ }
153
+ }
154
+
155
+ }
156
+
157
+ private static class AnonymousMap implements SeekableByteChannel {
158
+ private final byte [] data ;
159
+
160
+ private boolean open = true ;
161
+ private int cur ;
162
+
163
+ public AnonymousMap (int cap ) {
164
+ this .data = new byte [cap ];
165
+ }
166
+
167
+ public boolean isOpen () {
168
+ return open ;
169
+ }
170
+
171
+ public void close () throws IOException {
172
+ open = false ;
173
+ }
174
+
175
+ public int read (ByteBuffer dst ) throws IOException {
176
+ int nread = Math .min (dst .remaining (), data .length - cur );
177
+ dst .put (data , cur , nread );
178
+ return nread ;
179
+ }
180
+
181
+ public int write (ByteBuffer src ) throws IOException {
182
+ int nwrite = Math .min (src .remaining (), data .length - cur );
183
+ src .get (data , cur , nwrite );
184
+ return nwrite ;
185
+ }
186
+
187
+ public long position () throws IOException {
188
+ return cur ;
189
+ }
190
+
191
+ public SeekableByteChannel position (long newPosition ) throws IOException {
192
+ if (newPosition < 0 || newPosition >= data .length ) {
193
+ throw new IllegalArgumentException ();
194
+ }
195
+ cur = (int ) newPosition ;
196
+ return this ;
197
+ }
198
+
199
+ public long size () throws IOException {
200
+ return data .length ;
201
+ }
202
+
203
+ public SeekableByteChannel truncate (long size ) throws IOException {
204
+ for (int i = 0 ; i < size ; i ++) {
205
+ data [i ] = 0 ;
206
+ }
207
+ return this ;
208
+ }
209
+
136
210
}
137
211
}
0 commit comments