Skip to content

Commit 3e462c1

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Support external/native methods in bytecode
TEST=ci Change-Id: I2827c95f7b4d4bfa40239369d3675ef6adba4ab2 Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439545 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent e69b7ea commit 3e462c1

File tree

11 files changed

+1366
-1149
lines changed

11 files changed

+1366
-1149
lines changed

pkg/dart2bytecode/docs/bytecode.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,11 @@ type ConstantDynamicCall extends ConstantPoolEntry {
789789
PackedObject selectorName;
790790
PackedObject argDesc;
791791
}
792+
793+
// Occupies 2 entries in the constant pool
794+
type ConstantExternalCall extends ConstantPoolEntry {
795+
Byte tag = 15;
796+
}
792797
```
793798

794799
### Exceptions table
@@ -1250,6 +1255,11 @@ Lookup and invoke instance method with arguments SP[-(F-1)], ..., SP[0].
12501255
ContantPool[D] is a ConstantDynamicCall specifying selector and
12511256
arguments descriptor.
12521257

1258+
#### ExternalCall D
1259+
1260+
Invoke body of an external method.
1261+
ContantPool[D] is a ConstantExternalCall.
1262+
12531263
#### ReturnTOS
12541264

12551265
Return to the caller using SP[0] as a result.

pkg/dart2bytecode/lib/assembler.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,11 @@ class BytecodeAssembler {
553553
_emitInstructionDF(Opcode.kDynamicCall, rd, rf);
554554
}
555555

556+
@pragma('vm:prefer-inline')
557+
void emitExternalCall(int rd) {
558+
_emitInstructionD(Opcode.kExternalCall, rd);
559+
}
560+
556561
@pragma('vm:prefer-inline')
557562
void emitLoadStatic(int rd) {
558563
_emitInstructionD(Opcode.kLoadStatic, rd);

pkg/dart2bytecode/lib/bytecode_generator.dart

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,11 @@ class BytecodeGenerator extends RecursiveVisitor {
781781
_genConstructorInitializers(node);
782782
}
783783
if (node.isExternal) {
784-
_genNoSuchMethodForExternal(node);
784+
if (getExternalName(coreTypes, node) != null) {
785+
_genExternalCall(node);
786+
} else {
787+
_genNoSuchMethodForExternal(node);
788+
}
785789
} else {
786790
_generateNode(node.function?.body);
787791
// BytecodeAssembler eliminates this bytecode if it is unreachable.
@@ -852,6 +856,31 @@ class BytecodeGenerator extends RecursiveVisitor {
852856
return false;
853857
}
854858

859+
void _genExternalCall(Member node) {
860+
final function = node.function!;
861+
862+
if (locals.hasFactoryTypeArgsVar) {
863+
asm.emitPush(locals.getVarIndexInFrame(locals.factoryTypeArgsVar));
864+
} else if (locals.hasFunctionTypeArgsVar) {
865+
asm.emitPush(locals.functionTypeArgsVarIndexInFrame);
866+
}
867+
if (locals.hasReceiver) {
868+
asm.emitPush(locals.getVarIndexInFrame(locals.receiverVar));
869+
}
870+
for (var param in function.positionalParameters) {
871+
asm.emitPush(locals.getVarIndexInFrame(param));
872+
}
873+
// Native methods access their parameters by indices, so
874+
// native wrappers should pass arguments in the original declaration
875+
// order instead of sorted order.
876+
for (var param in locals.originalNamedParameters) {
877+
asm.emitPush(locals.getVarIndexInFrame(param));
878+
}
879+
880+
final externalCallCpIndex = cp.addExternalCall();
881+
asm.emitExternalCall(externalCallCpIndex);
882+
}
883+
855884
LibraryIndex get libraryIndex => coreTypes.index;
856885

857886
late Procedure growableListLiteral =

pkg/dart2bytecode/lib/constant_pool.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum ConstantTag {
3030
kInterfaceCall,
3131
kInstantiatedInterfaceCall,
3232
kDynamicCall,
33+
kExternalCall,
3334
}
3435

3536
String constantTagToString(ConstantTag tag) =>
@@ -84,6 +85,8 @@ abstract class ConstantPoolEntry {
8485
return new ConstantInstantiatedInterfaceCall.read(reader);
8586
case ConstantTag.kDynamicCall:
8687
return new ConstantDynamicCall.read(reader);
88+
case ConstantTag.kExternalCall:
89+
return new ConstantExternalCall.read(reader);
8790
}
8891
throw 'Unexpected constant tag $tag';
8992
}
@@ -501,6 +504,32 @@ class ConstantDynamicCall extends ConstantPoolEntry {
501504
this.argDesc == other.argDesc;
502505
}
503506

507+
class ConstantExternalCall extends ConstantPoolEntry {
508+
ConstantExternalCall();
509+
510+
@override
511+
ConstantTag get tag => ConstantTag.kExternalCall;
512+
513+
@override
514+
int get numReservedEntries => 1;
515+
516+
@override
517+
void writeValue(BufferedWriter writer) {}
518+
519+
ConstantExternalCall.read(BufferedReader reader);
520+
521+
@override
522+
String toString() => 'ExternalCall';
523+
524+
// Do not merge ConstantExternalCall entries.
525+
526+
@override
527+
int get hashCode => identityHashCode(this);
528+
529+
@override
530+
bool operator ==(other) => identical(this, other);
531+
}
532+
504533
/// Reserved constant pool entry.
505534
class _ReservedConstantPoolEntry extends ConstantPoolEntry {
506535
const _ReservedConstantPoolEntry();
@@ -576,6 +605,8 @@ class ConstantPool {
576605
? addDynamicCall(invocationKind, targetName, argDesc)
577606
: addInterfaceCall(invocationKind, target, argDesc);
578607

608+
int addExternalCall() => _add(ConstantExternalCall());
609+
579610
int addStaticField(Field field) =>
580611
_add(new ConstantStaticField(objectTable.getHandle(field)!));
581612

pkg/dart2bytecode/lib/dbc.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ enum Opcode {
135135
kUncheckedDirectCall_Wide,
136136
kInterfaceCall,
137137
kInterfaceCall_Wide,
138-
kUnused23, // Reserved for InterfaceCall1
139-
kUnused24, // Reserved for InterfaceCall1_Wide
138+
kExternalCall,
139+
kExternalCall_Wide,
140140
kInstantiatedInterfaceCall,
141141
kInstantiatedInterfaceCall_Wide,
142142
kUncheckedClosureCall,
@@ -372,6 +372,8 @@ const Map<Opcode, Format> BytecodeFormats = const {
372372
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
373373
Opcode.kDynamicCall: const Format(
374374
Encoding.kDF, const [Operand.lit, Operand.imm, Operand.none]),
375+
Opcode.kExternalCall: const Format(
376+
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
375377
Opcode.kReturnTOS: const Format(
376378
Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
377379
Opcode.kAssertAssignable: const Format(

runtime/vm/bytecode_reader.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
463463
kInterfaceCall,
464464
kInstantiatedInterfaceCall,
465465
kDynamicCall,
466+
kExternalCall,
466467
};
467468

468469
Object& obj = Object::Handle(Z);
@@ -617,6 +618,21 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
617618
// The second entry is used for arguments descriptor.
618619
obj = ReadObject();
619620
} break;
621+
case ConstantPoolTag::kExternalCall: {
622+
// ExternalCall constant occupies 2 entries:
623+
// trampoline and native function.
624+
pool.SetTypeAt(i, ObjectPool::EntryType::kNativeFunction,
625+
ObjectPool::Patchability::kNotPatchable,
626+
ObjectPool::SnapshotBehavior::kNotSnapshotable);
627+
pool.SetRawValueAt(i, 0);
628+
++i;
629+
ASSERT(i < obj_count);
630+
pool.SetTypeAt(i, ObjectPool::EntryType::kNativeFunction,
631+
ObjectPool::Patchability::kNotPatchable,
632+
ObjectPool::SnapshotBehavior::kNotSnapshotable);
633+
pool.SetRawValueAt(i, 0);
634+
continue;
635+
}
620636
default:
621637
UNREACHABLE();
622638
}

0 commit comments

Comments
 (0)