Skip to content

Commit fd848f1

Browse files
refactor(bindgen): rework lowers for variant based types
1 parent d101143 commit fd848f1

4 files changed

Lines changed: 301 additions & 159 deletions

File tree

crates/js-component-bindgen/src/intrinsics/lift.rs

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -590,29 +590,41 @@ impl LiftIntrinsic {
590590
Self::LiftFlatFloat64 => {
591591
let debug_log_fn = Intrinsic::DebugLog.name();
592592
let lift_flat_f64_fn = self.name();
593-
output.push_str(&format!("
594-
function {lift_flat_f64_fn}(ctx) {{
595-
{debug_log_fn}('[{lift_flat_f64_fn}()] args', {{ ctx }});
596-
let val;
597-
598-
if (ctx.useDirectParams) {{
599-
if (ctx.params.length === 0) {{ throw new Error('expected at least one single f64 argument'); }}
600-
val = ctx.params[0];
601-
ctx.params = ctx.params.slice(1);
602-
return [val, ctx];
603-
}}
604-
605-
if (ctx.storageLen !== undefined && ctx.storageLen < 8) {{
606-
throw new Error(`insufficient storage ([${{ctx.storageLen}}] bytes) for lift (f64 requires 8 bytes)`);
607-
}}
608-
609-
val = new DataView(ctx.memory.buffer).getFloat64(ctx.storagePtr, true);
610-
ctx.storagePtr += 8;
611-
if (ctx.storageLen !== undefined) {{ ctx.storageLen -= 8; }}
612-
613-
return [val, ctx];
614-
}}
615-
"));
593+
uwriteln!(
594+
output,
595+
r#"
596+
function {lift_flat_f64_fn}(ctx) {{
597+
{debug_log_fn}('[{lift_flat_f64_fn}()] args', {{ ctx }});
598+
let val;
599+
600+
if (ctx.useDirectParams) {{
601+
if (ctx.params.length === 0) {{
602+
throw new Error('expected at least one single f64 argument');
603+
}}
604+
val = ctx.params[0];
605+
ctx.params = ctx.params.slice(1);
606+
607+
if (ctx.inVariant) {{
608+
const dv = new DataView(new ArrayBuffer(8));
609+
dv.setBigInt64(0, val);
610+
val = dv.getFloat64(0);
611+
}}
612+
613+
return [val, ctx];
614+
}}
615+
616+
if (ctx.storageLen !== undefined && ctx.storageLen < 8) {{
617+
throw new Error(`insufficient storage ([${{ctx.storageLen}}] bytes) for lift (f64 requires 8 bytes)`);
618+
}}
619+
620+
val = new DataView(ctx.memory.buffer).getFloat64(ctx.storagePtr, true);
621+
ctx.storagePtr += 8;
622+
if (ctx.storageLen !== undefined) {{ ctx.storageLen -= 8; }}
623+
624+
return [val, ctx];
625+
}}
626+
"#
627+
);
616628
}
617629

618630
Self::LiftFlatChar => {
@@ -674,8 +686,9 @@ impl LiftIntrinsic {
674686
675687
if (ctx.useDirectParams) {{
676688
if (ctx.params.length < 2) {{ throw new Error('expected at least two u32 arguments'); }}
677-
const offset = ctx.params[0];
678-
if (!Number.isSafeInteger(offset)) {{ throw new Error('invalid offset'); }}
689+
let offset = ctx.params[0];
690+
if (typeof offset === 'bigint') {{ offset = Number(offset); }}
691+
if (!Number.isSafeInteger(offset)) {{ throw new Error('invalid offset'); }}
679692
const len = ctx.params[1];
680693
if (!Number.isSafeInteger(len)) {{ throw new Error('invalid len'); }}
681694
val = {decoder}.decode(new DataView(ctx.memory.buffer, offset, len));
@@ -712,6 +725,7 @@ impl LiftIntrinsic {
712725
if (ctx.useDirectParams) {{
713726
if (ctx.params.length < 2) {{ throw new Error('expected at least two u32 arguments'); }}
714727
const offset = ctx.params[0];
728+
if (typeof offset === 'bigint') {{ offset = Number(offset); }}
715729
if (!Number.isSafeInteger(offset)) {{ throw new Error('invalid offset'); }}
716730
const len = ctx.params[1];
717731
if (!Number.isSafeInteger(len)) {{ throw new Error('invalid len'); }}
@@ -797,11 +811,21 @@ impl LiftIntrinsic {
797811
let lift_u8 = Self::LiftFlatU8.name();
798812
let lift_u16 = Self::LiftFlatU16.name();
799813
let lift_u32 = Self::LiftFlatU32.name();
814+
let lift_f64 = Self::LiftFlatFloat64.name();
815+
800816
output.push_str(&format!(r#"
801-
function {lift_flat_variant_fn}(casesAndLiftFns) {{
817+
function {lift_flat_variant_fn}(meta) {{
818+
const {{
819+
caseMetas,
820+
variantSize32,
821+
variantAlign32,
822+
variantPayloadOffset32,
823+
variantFlatCount,
824+
isEnum,
825+
}} = meta;
826+
802827
return function {lift_flat_variant_fn}Inner(ctx) {{
803828
{debug_log_fn}('[{lift_flat_variant_fn}()] args', {{ ctx }});
804-
805829
const origUseParams = ctx.useDirectParams;
806830
807831
// If we're in the process of lifting a variant, we note
@@ -812,8 +836,8 @@ impl LiftIntrinsic {
812836
let caseIdx;
813837
let liftRes;
814838
const originalPtr = ctx.storagePtr;
815-
const numCases = casesAndLiftFns.length;
816-
if (casesAndLiftFns.length < 256) {{
839+
const numCases = caseMetas.length;
840+
if (caseMetas.length < 256) {{
817841
liftRes = {lift_u8}(ctx);
818842
}} else if (numCases >= 256 && numCases < 65536) {{
819843
liftRes = {lift_u16}(ctx);
@@ -825,11 +849,20 @@ impl LiftIntrinsic {
825849
caseIdx = liftRes[0];
826850
ctx = liftRes[1];
827851
828-
const [ tag, liftFn, size32, align32, payloadOffset32, caseFlatCount, variantFlatCount ] = casesAndLiftFns[caseIdx];
829-
if (payloadOffset32 === undefined) {{ throw new Error('unexpectedly missing payload offset'); }}
852+
const [
853+
tag,
854+
liftFn,
855+
caseSize32,
856+
caseAlign32,
857+
caseFlatCount,
858+
] = caseMetas[caseIdx];
859+
860+
if (variantPayloadOffset32 === undefined) {{
861+
throw new Error('unexpectedly missing payload offset');
862+
}}
830863
831864
if (originalPtr !== undefined) {{
832-
ctx.storagePtr = originalPtr + payloadOffset32;
865+
ctx.storagePtr = originalPtr + variantPayloadOffset32;
833866
}}
834867
835868
let val;
@@ -838,28 +871,32 @@ impl LiftIntrinsic {
838871
// NOTE: here we need to move past the entire object in memory
839872
// despite moving to the payload which we now know is missing/unnecessary
840873
if (originalPtr !== undefined) {{
841-
ctx.storagePtr = originalPtr + size32;
874+
ctx.storagePtr = originalPtr + variantSize32;
842875
}}
843876
}} else {{
877+
if (ctx.useDirectParams && ctx.params && liftFn !== {lift_f64} && typeof ctx.params[0] === 'bigint') {{
878+
if (ctx.params[0] > BigInt(Number.MAX_SAFE_INTEGER)) {{
879+
throw new Error(`invalid value, reinterpreted i32/f32 too large: [${{ctx.params[0]}}]`);
880+
}}
881+
ctx.params[0] = Number(ctx.params[0]);
882+
}}
883+
844884
const [newVal, newCtx] = liftFn(ctx);
845885
val = {{ tag, val: newVal }};
846886
ctx = newCtx;
847-
848-
// NOTE: Padding can be left over after doing the lift if it was less than
849-
// space left for the payload normally.
850-
if (originalPtr !== undefined) {{
851-
ctx.storagePtr = Math.max(ctx.storagePtr, originalPtr + size32);
852-
}}
853887
}}
854888
855889
if (origUseParams) {{
856-
if (caseFlatCount === undefined || variantFlatCount === undefined) {{
857-
throw new Error('variant flat count metadata is missing');
858-
}}
859-
if (caseFlatCount === null || variantFlatCount === null) {{
890+
if (variantFlatCount === undefined || variantFlatCount === null) {{
891+
{debug_log_fn}('[{lift_flat_variant_fn}()] variant with unknown flat count', {{ ctx, meta }});
860892
throw new Error('cannot lift variant with unknown flat count');
861893
}}
862-
const remainingPayloadParams = variantFlatCount - 1 - caseFlatCount;
894+
if (caseFlatCount === undefined || caseFlatCount === null) {{
895+
{debug_log_fn}('[{lift_flat_variant_fn}()] case with unknown flat count', {{ ctx, meta, case: meta.caseMetas[caseIdx] }});
896+
throw new Error('cannot lift case with unknown flat count');
897+
}}
898+
// NOTE: enums can be tightly packed and do not have a descriminant
899+
const remainingPayloadParams = variantFlatCount - caseFlatCount - (isEnum ? 0 : 1);
863900
if (remainingPayloadParams < 0) {{
864901
throw new Error(`invalid variant flat count metadata`);
865902
}}
@@ -870,8 +907,8 @@ impl LiftIntrinsic {
870907
}}
871908
872909
if (ctx.storagePtr !== undefined) {{
873-
const rem = ctx.storagePtr % align32;
874-
if (rem !== 0) {{ ctx.storagePtr += align32 - rem; }}
910+
const rem = ctx.storagePtr % variantAlign32;
911+
if (rem !== 0) {{ ctx.storagePtr += variantAlign32 - rem; }}
875912
}}
876913
877914
ctx.inVariant = wasInVariant;
@@ -1040,10 +1077,12 @@ impl LiftIntrinsic {
10401077
let lift_flat_enum_fn = self.name();
10411078
output.push_str(&format!(
10421079
r#"
1043-
function {lift_flat_enum_fn}(casesAndLiftFns) {{
1080+
function {lift_flat_enum_fn}(meta) {{
1081+
meta.isEnum = true;
1082+
const f = {lift_variant}(meta);
10441083
return function {lift_flat_enum_fn}Inner(ctx) {{
10451084
{debug_log_fn}('[{lift_flat_enum_fn}()] args', {{ ctx }});
1046-
const res = {lift_variant}(casesAndLiftFns)(ctx);
1085+
const res = f(ctx);
10471086
res[0] = res[0].tag;
10481087
return res;
10491088
}}
@@ -1058,10 +1097,11 @@ impl LiftIntrinsic {
10581097
let lift_flat_option_fn = self.name();
10591098
output.push_str(&format!(
10601099
r#"
1061-
function {lift_flat_option_fn}(casesAndLiftFns) {{
1100+
function {lift_flat_option_fn}(meta) {{
1101+
const f = {lift_variant}(meta);
10621102
return function {lift_flat_option_fn}Inner(ctx) {{
10631103
{debug_log_fn}('[{lift_flat_option_fn}()] args', {{ ctx }});
1064-
return {lift_variant}(casesAndLiftFns)(ctx);
1104+
return f(ctx);
10651105
}}
10661106
}}
10671107
"#
@@ -1074,10 +1114,11 @@ impl LiftIntrinsic {
10741114
let lift_flat_result_fn = self.name();
10751115
output.push_str(&format!(
10761116
r#"
1077-
function {lift_flat_result_fn}(casesAndLiftFns) {{
1117+
function {lift_flat_result_fn}(meta) {{
1118+
const f = {lift_variant}(meta);
10781119
return function {lift_flat_result_fn}Inner(ctx) {{
10791120
{debug_log_fn}('[{lift_flat_result_fn}()] args', {{ ctx }});
1080-
return {lift_variant}(casesAndLiftFns)(ctx);
1121+
return f(ctx);
10811122
}}
10821123
}}
10831124
"#

crates/js-component-bindgen/src/intrinsics/lower.rs

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -648,9 +648,11 @@ impl LowerIntrinsic {
648648
let lower_u32_fn = Self::LowerFlatU32.name();
649649

650650
output.push_str(&format!(r#"
651-
function {lower_flat_variant_fn}(lowerMetas) {{
651+
function {lower_flat_variant_fn}(meta) {{
652+
const {{ variantSize32, variantAlign32, variantPayloadOffset32, caseMetas }} = meta;
653+
652654
let caseLookup = {{}};
653-
for (const [idx, meta] of lowerMetas.entries()) {{
655+
for (const [idx, meta] of caseMetas.entries()) {{
654656
let tag = meta[0];
655657
caseLookup[tag] = {{ discriminant: idx, meta }};
656658
}}
@@ -664,30 +666,30 @@ impl LowerIntrinsic {
664666
throw new Error(`missing tag [${{tag}}] (valid tags: ${{Object.keys(caseLookup)}})`);
665667
}}
666668
667-
const [ _tag, lowerFn, size32, align32, payloadOffset32 ] = variantCase.meta;
669+
const [ _tag, lowerFn, caseSize32, caseAlign32, caseFlatCount ] = variantCase.meta;
668670
669671
const originalPtr = ctx.storagePtr;
670672
ctx.vals = [variantCase.discriminant];
671673
let discLowerRes;
672-
if (lowerMetas.length < 256) {{
674+
if (caseMetas.length < 256) {{
673675
discLowerRes = {lower_u8_fn}(ctx);
674-
}} else if (lowerMetas.length >= 256 && lowerMetas.length < 65536) {{
676+
}} else if (caseMetas.length >= 256 && caseMetas.length < 65536) {{
675677
discLowerRes = {lower_u16_fn}(ctx);
676-
}} else if (lowerMetas.length >= 65536 && lowerMetas.length < 4_294_967_296) {{
678+
}} else if (caseMetas.length >= 65536 && caseMetas.length < 4_294_967_296) {{
677679
discLowerRes = {lower_u32_fn}(ctx);
678680
}} else {{
679-
throw new Error(`unsupported number of cases [${{lowerMetas.length}}]`);
681+
throw new Error(`unsupported number of cases [${{caseMetas.length}}]`);
680682
}}
681683
682-
const payloadOffsetPtr = originalPtr + payloadOffset32;
684+
const payloadOffsetPtr = originalPtr + variantPayloadOffset32;
683685
ctx.storagePtr = payloadOffsetPtr;
684686
ctx.vals = [val];
685687
if (lowerFn) {{ lowerFn(ctx); }}
686688
687-
ctx.storagePtr = Math.max(ctx.storagePtr, originalPtr + size32);
689+
ctx.storagePtr = Math.max(ctx.storagePtr, originalPtr + variantSize32);
688690
689-
const rem = ctx.storagePtr % align32;
690-
if (rem !== 0) {{ ctx.storagePtr += align32 - rem; }}
691+
const rem = ctx.storagePtr % variantAlign32;
692+
if (rem !== 0) {{ ctx.storagePtr += varianttAlign32 - rem; }}
691693
}}
692694
}}
693695
"#));
@@ -883,7 +885,8 @@ impl LowerIntrinsic {
883885

884886
output.push_str(&format!(
885887
r#"
886-
function {lower_flat_enum_fn}(lowerMetas) {{
888+
function {lower_flat_enum_fn}(meta) {{
889+
const f = {lower_variant_fn}(meta);
887890
return function {lower_flat_enum_fn}Inner(ctx) {{
888891
{debug_log_fn}('[{lower_flat_enum_fn}()] args', {{ ctx }});
889892
@@ -895,7 +898,7 @@ impl LowerIntrinsic {
895898
ctx.vals[0] = {{ tag: v }};
896899
}}
897900
898-
{lower_variant_fn}(lowerMetas)(ctx);
901+
f(ctx);
899902
}}
900903
}}
901904
"#
@@ -909,7 +912,8 @@ impl LowerIntrinsic {
909912

910913
output.push_str(&format!(
911914
"
912-
function {lower_flat_option_fn}(lowerMetas) {{
915+
function {lower_flat_option_fn}(meta) {{
916+
const f = {lower_variant_fn}(meta);
913917
return function {lower_flat_option_fn}Inner(ctx) {{
914918
{debug_log_fn}('[{lower_flat_option_fn}()] args', {{ ctx }});
915919
@@ -927,7 +931,7 @@ impl LowerIntrinsic {
927931
}}
928932
}}
929933
930-
{lower_variant_fn}(lowerMetas)(ctx);
934+
f(ctx);
931935
}}
932936
}}
933937
"
@@ -938,11 +942,13 @@ impl LowerIntrinsic {
938942
let debug_log_fn = Intrinsic::DebugLog.name();
939943
let lower_flat_result_fn = self.name();
940944
let lower_variant_fn = Self::LowerFlatVariant.name();
945+
941946
output.push_str(&format!(
942947
r#"
943-
function {lower_flat_result_fn}(lowerMetas) {{
948+
function {lower_flat_result_fn}(meta) {{
949+
const f = {lower_variant_fn}(meta);
944950
return function {lower_flat_result_fn}Inner(ctx) {{
945-
{debug_log_fn}('[{lower_flat_result_fn}()] args', {{ lowerMetas }});
951+
{debug_log_fn}('[{lower_flat_result_fn}()] args', {{ ctx }});
946952
947953
const v = ctx.vals[0];
948954
const isNotResultObject = typeof v !== 'object'
@@ -954,7 +960,7 @@ impl LowerIntrinsic {
954960
ctx.vals[0] = {{ tag: 'ok', val: v }};
955961
}}
956962
957-
{lower_variant_fn}(lowerMetas)(ctx);
963+
f(ctx);
958964
}};
959965
}}
960966
"#

crates/js-component-bindgen/src/intrinsics/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,7 @@ pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
13741374
&Intrinsic::Lift(LiftIntrinsic::LiftFlatU8),
13751375
&Intrinsic::Lift(LiftIntrinsic::LiftFlatU16),
13761376
&Intrinsic::Lift(LiftIntrinsic::LiftFlatU32),
1377+
&Intrinsic::Lift(LiftIntrinsic::LiftFlatFloat64),
13771378
]);
13781379
}
13791380

0 commit comments

Comments
 (0)