Skip to content

Commit 469b8ca

Browse files
refactor(bindgen): rework lowers for variant based types
1 parent cca8eee commit 469b8ca

3 files changed

Lines changed: 296 additions & 152 deletions

File tree

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

Lines changed: 89 additions & 45 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 => {
@@ -797,11 +809,21 @@ impl LiftIntrinsic {
797809
let lift_u8 = Self::LiftFlatU8.name();
798810
let lift_u16 = Self::LiftFlatU16.name();
799811
let lift_u32 = Self::LiftFlatU32.name();
812+
let lift_f64 = Self::LiftFlatFloat64.name();
813+
800814
output.push_str(&format!(r#"
801-
function {lift_flat_variant_fn}(casesAndLiftFns) {{
815+
function {lift_flat_variant_fn}(meta) {{
816+
const {{
817+
caseMetas,
818+
variantSize32,
819+
variantAlign32,
820+
variantPayloadOffset32,
821+
variantFlatCount,
822+
isEnum,
823+
}} = meta;
824+
802825
return function {lift_flat_variant_fn}Inner(ctx) {{
803826
{debug_log_fn}('[{lift_flat_variant_fn}()] args', {{ ctx }});
804-
805827
const origUseParams = ctx.useDirectParams;
806828
807829
// If we're in the process of lifting a variant, we note
@@ -812,8 +834,8 @@ impl LiftIntrinsic {
812834
let caseIdx;
813835
let liftRes;
814836
const originalPtr = ctx.storagePtr;
815-
const numCases = casesAndLiftFns.length;
816-
if (casesAndLiftFns.length < 256) {{
837+
const numCases = caseMetas.length;
838+
if (caseMetas.length < 256) {{
817839
liftRes = {lift_u8}(ctx);
818840
}} else if (numCases >= 256 && numCases < 65536) {{
819841
liftRes = {lift_u16}(ctx);
@@ -825,11 +847,20 @@ impl LiftIntrinsic {
825847
caseIdx = liftRes[0];
826848
ctx = liftRes[1];
827849
828-
const [ tag, liftFn, size32, align32, payloadOffset32, caseFlatCount, variantFlatCount ] = casesAndLiftFns[caseIdx];
829-
if (payloadOffset32 === undefined) {{ throw new Error('unexpectedly missing payload offset'); }}
850+
const [
851+
tag,
852+
liftFn,
853+
caseSize32,
854+
caseAlign32,
855+
caseFlatCount,
856+
] = caseMetas[caseIdx];
857+
858+
if (variantPayloadOffset32 === undefined) {{
859+
throw new Error('unexpectedly missing payload offset');
860+
}}
830861
831862
if (originalPtr !== undefined) {{
832-
ctx.storagePtr = originalPtr + payloadOffset32;
863+
ctx.storagePtr = originalPtr + variantPayloadOffset32;
833864
}}
834865
835866
let val;
@@ -838,28 +869,37 @@ impl LiftIntrinsic {
838869
// NOTE: here we need to move past the entire object in memory
839870
// despite moving to the payload which we now know is missing/unnecessary
840871
if (originalPtr !== undefined) {{
841-
ctx.storagePtr = originalPtr + size32;
872+
// NOTE: THIS IS ZERO OTHERWISE
873+
ctx.storagePtr = originalPtr + variantSize32;
842874
}}
843875
}} else {{
876+
if (ctx.ctxUseDirectParams && ctx.params && liftFn !== {lift_f64} && typeof ctx.params[0] === 'bigint') {{
877+
if (ctx.params[0] > BigInt(Number.MAX_SAFE_INTEGER)) {{
878+
throw new Error(`invalid value, reinterpreted i32/f32 too large: [${{ctx.params[0]}}]`);
879+
}}
880+
ctx.params[0] = Number(ctx.params[0]);
881+
}}
882+
844883
const [newVal, newCtx] = liftFn(ctx);
845884
val = {{ tag, val: newVal }};
846885
ctx = newCtx;
847886
848887
// NOTE: Padding can be left over after doing the lift if it was less than
849888
// space left for the payload normally.
850889
if (originalPtr !== undefined) {{
851-
ctx.storagePtr = Math.max(ctx.storagePtr, originalPtr + size32);
890+
ctx.storagePtr = Math.max(ctx.storagePtr, originalPtr + caseSize32);
852891
}}
853892
}}
854893
855894
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) {{
895+
if (variantFlatCount === undefined || variantFlatCount === null) {{
860896
throw new Error('cannot lift variant with unknown flat count');
861897
}}
862-
const remainingPayloadParams = variantFlatCount - 1 - caseFlatCount;
898+
if (caseFlatCount === undefined || caseFlatCount === null) {{
899+
throw new Error('cannot lift case with unknown flat count');
900+
}}
901+
// NOTE: enums can be tightly packed and do not have a descriminant
902+
const remainingPayloadParams = variantFlatCount - caseFlatCount - (isEnum ? 0 : 1);
863903
if (remainingPayloadParams < 0) {{
864904
throw new Error(`invalid variant flat count metadata`);
865905
}}
@@ -870,8 +910,8 @@ impl LiftIntrinsic {
870910
}}
871911
872912
if (ctx.storagePtr !== undefined) {{
873-
const rem = ctx.storagePtr % align32;
874-
if (rem !== 0) {{ ctx.storagePtr += align32 - rem; }}
913+
const rem = ctx.storagePtr % variantAlign32;
914+
if (rem !== 0) {{ ctx.storagePtr += variantAlign32 - rem; }}
875915
}}
876916
877917
ctx.inVariant = wasInVariant;
@@ -1040,10 +1080,12 @@ impl LiftIntrinsic {
10401080
let lift_flat_enum_fn = self.name();
10411081
output.push_str(&format!(
10421082
r#"
1043-
function {lift_flat_enum_fn}(casesAndLiftFns) {{
1083+
function {lift_flat_enum_fn}(meta) {{
1084+
meta.isEnum = true;
1085+
const f = {lift_variant}(meta);
10441086
return function {lift_flat_enum_fn}Inner(ctx) {{
10451087
{debug_log_fn}('[{lift_flat_enum_fn}()] args', {{ ctx }});
1046-
const res = {lift_variant}(casesAndLiftFns)(ctx);
1088+
const res = f(ctx);
10471089
res[0] = res[0].tag;
10481090
return res;
10491091
}}
@@ -1058,10 +1100,11 @@ impl LiftIntrinsic {
10581100
let lift_flat_option_fn = self.name();
10591101
output.push_str(&format!(
10601102
r#"
1061-
function {lift_flat_option_fn}(casesAndLiftFns) {{
1103+
function {lift_flat_option_fn}(meta) {{
1104+
const f = {lift_variant}(meta);
10621105
return function {lift_flat_option_fn}Inner(ctx) {{
10631106
{debug_log_fn}('[{lift_flat_option_fn}()] args', {{ ctx }});
1064-
return {lift_variant}(casesAndLiftFns)(ctx);
1107+
return f(ctx);
10651108
}}
10661109
}}
10671110
"#
@@ -1074,10 +1117,11 @@ impl LiftIntrinsic {
10741117
let lift_flat_result_fn = self.name();
10751118
output.push_str(&format!(
10761119
r#"
1077-
function {lift_flat_result_fn}(casesAndLiftFns) {{
1120+
function {lift_flat_result_fn}(meta) {{
1121+
const f = {lift_variant}(meta);
10781122
return function {lift_flat_result_fn}Inner(ctx) {{
10791123
{debug_log_fn}('[{lift_flat_result_fn}()] args', {{ ctx }});
1080-
return {lift_variant}(casesAndLiftFns)(ctx);
1124+
return f(ctx);
10811125
}}
10821126
}}
10831127
"#

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
"#

0 commit comments

Comments
 (0)