13
13
import java .util .Arrays ;
14
14
import java .util .concurrent .locks .ReentrantLock ;
15
15
16
+ import com .oracle .truffle .api .CompilerAsserts ;
16
17
import com .oracle .truffle .api .TruffleSafepoint ;
17
18
import com .oracle .truffle .api .dsl .Bind ;
18
19
import com .oracle .truffle .api .dsl .GenerateCached ;
@@ -714,7 +715,7 @@ public abstract static class RbEncCodeRangeClear extends CoreMethodArrayArgument
714
715
@ Specialization
715
716
RubyString clearCodeRange (RubyString string ,
716
717
@ Cached StringToNativeNode stringToNativeNode ) {
717
- stringToNativeNode .executeToNative (this , string );
718
+ stringToNativeNode .executeToNative (this , string , true );
718
719
string .clearCodeRange ();
719
720
720
721
return string ;
@@ -817,7 +818,7 @@ public abstract static class RbStrCapacityNode extends CoreMethodArrayArgumentsN
817
818
@ Specialization
818
819
long capacity (Object string ,
819
820
@ Cached StringToNativeNode stringToNativeNode ) {
820
- return getNativeStringCapacity (stringToNativeNode .executeToNative (this , string ));
821
+ return getNativeStringCapacity (stringToNativeNode .executeToNative (this , string , true ));
821
822
}
822
823
}
823
824
@@ -830,7 +831,7 @@ RubyString strSetLen(RubyString string, int newByteLength,
830
831
@ Cached StringToNativeNode stringToNativeNode ,
831
832
@ Cached MutableTruffleString .FromNativePointerNode fromNativePointerNode ,
832
833
@ Cached InlinedConditionProfile minLengthOneProfile ) {
833
- var pointer = stringToNativeNode .executeToNative (this , string );
834
+ var pointer = stringToNativeNode .executeToNative (this , string , true );
834
835
835
836
var encoding = libString .getEncoding (string );
836
837
int minLength = encoding .jcoding .minLength ();
@@ -860,7 +861,7 @@ RubyString rbStrResize(RubyString string, int newByteLength,
860
861
@ Cached RubyStringLibrary libString ,
861
862
@ Cached StringToNativeNode stringToNativeNode ,
862
863
@ Cached MutableTruffleString .FromNativePointerNode fromNativePointerNode ) {
863
- var pointer = stringToNativeNode .executeToNative (this , string );
864
+ var pointer = stringToNativeNode .executeToNative (this , string , true );
864
865
var tencoding = libString .getTEncoding (string );
865
866
int byteLength = string .tstring .byteLength (tencoding );
866
867
@@ -889,7 +890,7 @@ RubyString trStrCapaResize(RubyString string, int newCapacity,
889
890
@ Cached RubyStringLibrary libString ,
890
891
@ Cached StringToNativeNode stringToNativeNode ,
891
892
@ Cached MutableTruffleString .FromNativePointerNode fromNativePointerNode ) {
892
- var pointer = stringToNativeNode .executeToNative (this , string );
893
+ var pointer = stringToNativeNode .executeToNative (this , string , true );
893
894
var tencoding = libString .getTEncoding (string );
894
895
895
896
if (getNativeStringCapacity (pointer ) == newCapacity ) {
@@ -1327,24 +1328,29 @@ int rbHash(Object object,
1327
1328
}
1328
1329
}
1329
1330
1331
+ /** If inplace is true, this node mutates the RubyString to use native memory. It should be avoided unless there is
1332
+ * no other way because e.g. Regexp matching later on that String would then copy to managed byte[] back, and
1333
+ * copying back-and-forth is quite expensive. OTOH if the String will need to be used as native memory again soon
1334
+ * after and without needing to go to managed in between then it is valuable to avoid extra copies. */
1330
1335
@ GenerateInline
1331
1336
@ GenerateCached (false )
1332
1337
public abstract static class StringToNativeNode extends RubyBaseNode {
1333
1338
1334
- public abstract Pointer executeToNative (Node node , Object string );
1339
+ public abstract Pointer executeToNative (Node node , Object string , boolean inplace );
1335
1340
1336
1341
@ Specialization
1337
- static Pointer toNative (Node node , RubyString string ,
1342
+ static Pointer toNative (Node node , RubyString string , boolean inplace ,
1338
1343
@ Cached RubyStringLibrary libString ,
1339
1344
@ Cached InlinedConditionProfile convertProfile ,
1340
1345
@ Cached (inline = false ) TruffleString .CopyToNativeMemoryNode copyToNativeMemoryNode ,
1341
1346
@ Cached (inline = false ) MutableTruffleString .FromNativePointerNode fromNativePointerNode ,
1342
1347
@ Cached (inline = false ) TruffleString .GetInternalNativePointerNode getInternalNativePointerNode ) {
1348
+ CompilerAsserts .partialEvaluationConstant (inplace );
1349
+
1343
1350
var tstring = string .tstring ;
1344
1351
var tencoding = libString .getTEncoding (string );
1345
1352
1346
1353
final Pointer pointer ;
1347
-
1348
1354
if (convertProfile .profile (node , tstring .isNative ())) {
1349
1355
assert tstring .isMutable ();
1350
1356
pointer = (Pointer ) getInternalNativePointerNode .execute (tstring , tencoding );
@@ -1353,16 +1359,18 @@ static Pointer toNative(Node node, RubyString string,
1353
1359
pointer = allocateAndCopyToNative (getLanguage (node ), getContext (node ), tstring , tencoding , byteLength ,
1354
1360
copyToNativeMemoryNode );
1355
1361
1356
- var nativeTString = fromNativePointerNode .execute (pointer , 0 , byteLength , tencoding , false );
1357
- string .setTString (nativeTString );
1362
+ if (inplace ) {
1363
+ var nativeTString = fromNativePointerNode .execute (pointer , 0 , byteLength , tencoding , false );
1364
+ string .setTString (nativeTString );
1365
+ }
1358
1366
}
1359
1367
1360
1368
return pointer ;
1361
1369
}
1362
1370
1363
1371
@ Specialization
1364
- static Pointer toNativeImmutable (Node node , ImmutableRubyString string ) {
1365
- return string .getNativeString (getLanguage (node ));
1372
+ static Pointer toNativeImmutable (Node node , ImmutableRubyString string , boolean inplace ) {
1373
+ return string .getNativeString (getLanguage (node ), getContext ( node ) );
1366
1374
}
1367
1375
1368
1376
public static Pointer allocateAndCopyToNative (RubyLanguage language , RubyContext context ,
@@ -1381,17 +1389,34 @@ public abstract static class StringPointerToNativeNode extends PrimitiveArrayArg
1381
1389
@ Specialization
1382
1390
long toNative (Object string ,
1383
1391
@ Cached StringToNativeNode stringToNativeNode ) {
1384
- return stringToNativeNode .executeToNative (this , string ).getAddress ();
1392
+ return stringToNativeNode .executeToNative (this , string , true ).getAddress ();
1393
+ }
1394
+ }
1395
+
1396
+ @ CoreMethod (names = "string_to_ffi_pointer_inplace" , onSingleton = true , required = 1 )
1397
+ public abstract static class StringToFFIPointerInplaceNode extends CoreMethodArrayArgumentsNode {
1398
+
1399
+ @ Specialization
1400
+ RubyPointer toFFIPointerInplace (Object string ,
1401
+ @ Cached StringToNativeNode stringToNativeNode ) {
1402
+ var pointer = stringToNativeNode .executeToNative (this , string , true );
1403
+
1404
+ final RubyPointer instance = new RubyPointer (
1405
+ coreLibrary ().truffleFFIPointerClass ,
1406
+ getLanguage ().truffleFFIPointerShape ,
1407
+ pointer );
1408
+ AllocationTracing .trace (instance , this );
1409
+ return instance ;
1385
1410
}
1386
1411
}
1387
1412
1388
- @ CoreMethod (names = "string_to_ffi_pointer " , onSingleton = true , required = 1 )
1389
- public abstract static class StringToFFIPointerNode extends CoreMethodArrayArgumentsNode {
1413
+ @ CoreMethod (names = "string_to_ffi_pointer_copy " , onSingleton = true , required = 1 )
1414
+ public abstract static class StringToFFIPointerCopyNode extends CoreMethodArrayArgumentsNode {
1390
1415
1391
1416
@ Specialization
1392
- RubyPointer toNative (Object string ,
1417
+ RubyPointer toFFIPointerCopy (Object string ,
1393
1418
@ Cached StringToNativeNode stringToNativeNode ) {
1394
- var pointer = stringToNativeNode .executeToNative (this , string );
1419
+ var pointer = stringToNativeNode .executeToNative (this , string , false );
1395
1420
1396
1421
final RubyPointer instance = new RubyPointer (
1397
1422
coreLibrary ().truffleFFIPointerClass ,
0 commit comments