Skip to content

Commit 2b82995

Browse files
mtdowlingadwsingh
authored andcommitted
Make various improvements to the VM
1 parent 766161a commit 2b82995

16 files changed

Lines changed: 447 additions & 250 deletions

File tree

aws/client/aws-client-rulesengine/src/jmh/java/software/amazon/smithy/java/aws/client/rulesengine/Bench.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,21 @@ public class Bench {
4040
private EndpointResolver endpointResolver;
4141
private EndpointResolverParams endpointParams;
4242

43+
private Model model;
44+
private ServiceShape service;
45+
private final RulesEngineBuilder engine = new RulesEngineBuilder();
46+
4347
@Setup
4448
public void setup() {
45-
var model = Model.assembler()
49+
model = Model.assembler()
4650
.discoverModels()
4751
.addImport(ResolverTest.class.getResource("s3.json"))
4852
.putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true)
4953
.assemble()
5054
.unwrap();
5155
model = customizeS3Model(model);
52-
var service = model.expectShape(ShapeId.from("com.amazonaws.s3#AmazonS3"), ServiceShape.class);
56+
service = model.expectShape(ShapeId.from("com.amazonaws.s3#AmazonS3"), ServiceShape.class);
5357

54-
var engine = new RulesEngineBuilder();
5558
var plugin = EndpointRulesPlugin.create(engine);
5659

5760
client = DynamicClient.builder()
@@ -61,17 +64,18 @@ public void setup() {
6164
.addPlugin(plugin)
6265
.build();
6366
endpointResolver = client.config().endpointResolver();
64-
var ctx = Context.create();
65-
ctx.put(EndpointSettings.REGION, "us-east-1");
66-
// ctx.put(EndpointRulesPlugin.ADDITIONAL_ENDPOINT_PARAMS, Map.of("ForcePathStyle", true));
6767

6868
var inputValue = client.createStruct(ShapeId.from("com.amazonaws.s3#GetObjectRequest"),
6969
Document.of(Map.of(
7070
"Bucket",
7171
Document.of("miked"),
72-
//, Document.of("foo"),
7372
"Key",
7473
Document.of("bar"))));
74+
75+
var ctx = Context.create();
76+
ctx.put(EndpointSettings.REGION, "us-east-1");
77+
// ctx.put(EndpointRulesPlugin.ADDITIONAL_ENDPOINT_PARAMS, Map.of("UseFIPS", true, "UseDualStack", true));
78+
7579
endpointParams = EndpointResolverParams.builder()
7680
.context(ctx)
7781
.inputValue(inputValue)
@@ -101,4 +105,17 @@ private static Model customizeS3Model(Model m) {
101105
public Object evaluate() throws Exception {
102106
return endpointResolver.resolveEndpoint(endpointParams).get();
103107
}
108+
109+
// public static final TraitKey<EndpointRuleSetTrait> ENDPOINT_RULESET_TRAIT =
110+
// TraitKey.get(EndpointRuleSetTrait.class);
111+
//
112+
// @Benchmark
113+
// public Object compileBdd() {
114+
// var ruleset = client.config().service().schema().getTrait(ENDPOINT_RULESET_TRAIT);
115+
// var cfg = Cfg.from(ruleset.getEndpointRuleSet());
116+
// var bdd = BddTrait.from(cfg).transform(SiftingOptimization.builder().cfg(cfg).build()).transform(new NodeReversal());
117+
// var bytecode = engine.compile(bdd);
118+
// var providers = engine.getBuiltinProviders();
119+
// return new BytecodeEndpointResolver(bytecode, engine.getExtensions(), providers);
120+
// }
104121
}

client/client-rulesengine/src/main/java/software/amazon/smithy/java/client/rulesengine/Bytecode.java

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,25 @@
5151
* <ol>
5252
* <li><b>Condition Table</b> - Array of 4-byte offsets pointing to each condition's bytecode</li>
5353
* <li><b>Result Table</b> - Array of 4-byte offsets pointing to each result's bytecode</li>
54+
* <li><b>Register Definitions</b> - Array of parameter/register metadata (immediately after result table)</li>
5455
* <li><b>Function Table</b> - Array of function names</li>
55-
* <li><b>Register Definitions</b> - Array of parameter/register metadata</li>
56-
* <li><b>BDD Table</b> - Array of BDD nodes</li>
56+
* <li><b>BDD Table</b> - Array of BDD nodes (3 ints per node)</li>
5757
* <li><b>Bytecode Section</b> - Compiled instructions for conditions and results</li>
5858
* <li><b>Constant Pool</b> - All constants referenced by the bytecode</li>
5959
* </ol>
6060
*
6161
* <h3>Condition Table</h3>
6262
* <p>Array of 4-byte offsets pointing to the start of each condition's bytecode.
63-
* Each offset is absolute from the start of the file.
63+
* Each offset is absolute from the start of the file. When loaded, these are
64+
* adjusted to be relative to the bytecode section start for efficient access.
6465
*
6566
* <h3>Result Table</h3>
6667
* <p>Array of 4-byte offsets pointing to the start of each result's bytecode.
67-
* Each offset is absolute from the start of the file.
68-
*
69-
* <h3>Function Table</h3>
70-
* <p>Array of function names used in the bytecode. Each function name is encoded as:
71-
* <pre>
72-
* [length:2][UTF-8 bytes]
73-
* </pre>
68+
* Each offset is absolute from the start of the file. When loaded, these are
69+
* adjusted to be relative to the bytecode section start for efficient access.
7470
*
7571
* <h3>Register Definitions</h3>
76-
* <p>Immediately follows the function table. Each register is encoded as:
72+
* <p>Immediately follows the result table. Each register is encoded as:
7773
* <pre>
7874
* [nameLen:2][name:UTF-8][required:1][temp:1][hasDefault:1][default:?][hasBuiltin:1][builtin:?]
7975
* </pre>
@@ -89,16 +85,38 @@
8985
* <li>builtin: UTF-8 encoded builtin name (only present if hasBuiltin=1)</li>
9086
* </ul>
9187
*
88+
* <h3>Function Table</h3>
89+
* <p>Array of function names used in the bytecode. Each function name is encoded as:
90+
* <pre>
91+
* [length:2][UTF-8 bytes]
92+
* </pre>
93+
*
9294
* <h3>BDD Table</h3>
9395
* <p>Array of BDD nodes for efficient condition evaluation. Each node is encoded as 12 bytes:
9496
* <pre>
9597
* [varIdx:4][highRef:4][lowRef:4]
9698
* </pre>
99+
* Where:
100+
* <ul>
101+
* <li>varIdx: Index of the condition to test (0-based)</li>
102+
* <li>highRef: Reference to follow if condition is true</li>
103+
* <li>lowRef: Reference to follow if condition is false</li>
104+
* </ul>
105+
*
106+
* <p>Reference encoding follows the BDD conventions:
107+
* <ul>
108+
* <li>1: TRUE terminal</li>
109+
* <li>-1: FALSE terminal</li>
110+
* <li>2, 3, ...: Node references (node at index ref-1)</li>
111+
* <li>-2, -3, ...: Complement node references (logical NOT)</li>
112+
* <li>100_000_000+: Result terminals (100_000_000 + resultIndex)</li>
113+
* </ul>
97114
*
98115
* <h3>Bytecode Section</h3>
99116
* <p>Contains the compiled bytecode instructions for all conditions and results.
100-
* The condition/result tables point to offsets within this section. Instructions
101-
* use a stack-based virtual machine with opcodes defined in {@link Opcodes}.
117+
* The condition/result tables contain absolute offsets from the start of the file that point into this section.
118+
* Instructions use a stack-based virtual machine with opcodes defined in {@link Opcodes}. This section may include
119+
* control flow instructions like JT_OR_POP for short-circuit evaluation.
102120
*
103121
* <h3>Constant Pool</h3>
104122
* <p>Contains all constants referenced by the bytecode. Each constant is prefixed
@@ -115,7 +133,7 @@
115133
* 5 MAP [count:2]([keyLen:2][key:UTF-8][value:?])...
116134
* </pre>
117135
*
118-
* <p>Lists and maps can contain nested values of any supported type.
136+
* <p>Lists and maps can contain nested values of any supported type, up to a maximum nesting depth of 100 levels.
119137
*
120138
* <h2>Usage</h2>
121139
*
@@ -171,6 +189,10 @@ public final class Bytecode {
171189
int[] bddNodes,
172190
int bddRootRef
173191
) {
192+
if (bddNodes.length % 3 != 0) {
193+
throw new IllegalArgumentException("BDD nodes length must be multiple of 3, got: " + bddNodes.length);
194+
}
195+
174196
this.bytecode = Objects.requireNonNull(bytecode);
175197
this.conditionOffsets = Objects.requireNonNull(conditionOffsets);
176198
this.resultOffsets = Objects.requireNonNull(resultOffsets);

client/client-rulesengine/src/main/java/software/amazon/smithy/java/client/rulesengine/BytecodeCompiler.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ final class BytecodeCompiler {
5555
this.builtinProviders = builtinProviders;
5656
this.availableFunctions = functions;
5757
this.bdd = bdd;
58-
this.registerAllocator = new RegisterAllocator.FlatAllocator();
58+
this.registerAllocator = new RegisterAllocator();
5959

6060
// Add parameters as registry values
6161
for (var param : bdd.getParameters()) {
@@ -110,7 +110,7 @@ Bytecode compile() {
110110
private void compileCondition(Condition condition) {
111111
compileExpression(condition.getFunction());
112112
condition.getResult().ifPresent(result -> {
113-
byte register = registerAllocator.shadow(result.toString());
113+
byte register = registerAllocator.getOrAllocateRegister(result.toString());
114114
writer.writeByte(Opcodes.SET_REGISTER);
115115
writer.writeByte(register);
116116
});
@@ -370,7 +370,7 @@ private void compileLiteral(Literal literal) {
370370
// Simple string with no interpolation
371371
addLoadConst(parts.get(0).toString());
372372
} else if (parts.size() == 1 && parts.get(0) instanceof Template.Dynamic dynamic) {
373-
// Single dynamic expression - just evaluate it
373+
// Single dynamic expression, so just evaluate it
374374
compileExpression(dynamic.toExpression());
375375
} else {
376376
// Multiple parts - need to concatenate
@@ -447,7 +447,6 @@ private Bytecode buildProgram() {
447447
var registerDefs = registerAllocator.getRegistry().toArray(new RegisterDefinition[0]);
448448
var fns = usedFunctions.toArray(new RulesFunction[0]);
449449

450-
// Extract BDD nodes to an array using the consumer approach
451450
Bdd bddData = bdd.getBdd();
452451
int nodeCount = bddData.getNodeCount();
453452
int[] bddNodes = new int[nodeCount * 3];

0 commit comments

Comments
 (0)