Skip to content

Commit 641ccd5

Browse files
committed
decode globals section
asm globals in wasm ecoding and populating WasmGlobal standin ReadExpr() read entire init_expr bounded by bEnd removed stale comment comment fixed issues codegen opcodes and section fixing comp errors bytecode generation part globals using ld/stslot working globals, before review better set globals offset when we run function section since globals section is optional EOLS, tabs fixes review feedback p1 renaming SetFunctionExport to SetExport review 2nd fixing tests getting rid of globalImportCount coercing imported globals according to WASM spec
1 parent 835028e commit 641ccd5

29 files changed

Lines changed: 655 additions & 98 deletions

lib/Runtime/Library/WasmLibrary.cpp

Lines changed: 174 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace Js
126126
{
127127
Wasm::WasmDataSegment* segment = wasmModule->GetDataSeg(iSeg);
128128
Assert(segment != nullptr);
129-
const uint32 offset = segment->getDestAddr();
129+
const uint32 offset = segment->getDestAddr(wasmModule);
130130
const uint32 size = segment->getSourceSize();
131131
if (offset > maxSize || UInt32Math::Add(offset, size) > maxSize)
132132
{
@@ -252,17 +252,86 @@ namespace Js
252252
{
253253
PropertyRecord const * propertyRecord = nullptr;
254254
ctx->GetOrAddPropertyRecord(funcExport->name, funcExport->nameLength, &propertyRecord);
255-
Var funcObj = GetFunctionObjFromFunctionIndex(wasmModule, ctx, funcExport->funcIndex, localModuleFunctions, importFunctions);
256-
if (!funcObj)
255+
256+
Var obj = ctx->GetLibrary()->GetUndefined();
257+
switch (funcExport->kind)
257258
{
258-
funcObj = ctx->GetLibrary()->GetUndefined();
259+
case Wasm::ExternalKinds::Function:
260+
261+
obj = GetFunctionObjFromFunctionIndex(wasmModule, ctx, funcExport->funcIndex, localModuleFunctions, importFunctions);
262+
break;
263+
case Wasm::ExternalKinds::Global:
264+
Wasm::WasmGlobal* global = wasmModule->globals.Item(funcExport->funcIndex);
265+
Assert(global->GetReferenceType() == Wasm::WasmGlobal::Const); //every global has to be resolved by this point
266+
267+
if (global->GetMutability())
268+
{
269+
throw Wasm::WasmCompilationException(_u("global %d is mutable. Exporting mutable globals isn't supported"), iExport);
270+
}
271+
272+
switch (global->GetType())
273+
{
274+
case Wasm::WasmTypes::I32:
275+
obj = JavascriptNumber::ToVar(global->cnst.i32, ctx);
276+
break;
277+
case Wasm::WasmTypes::F32:
278+
obj = JavascriptNumber::New((double)global->cnst.f32, ctx);
279+
break;
280+
case Wasm::WasmTypes::F64:
281+
obj = JavascriptNumber::New(global->cnst.f64, ctx);
282+
break;
283+
case Wasm::WasmTypes::I64:
284+
default:
285+
Assert(UNREACHED);
286+
break;
287+
}
259288
}
260-
JavascriptOperators::OP_SetProperty(exportsNamespace, propertyRecord->GetPropertyId(), funcObj, ctx);
289+
JavascriptOperators::OP_SetProperty(exportsNamespace, propertyRecord->GetPropertyId(), obj, ctx);
261290
}
262291
}
263292
}
264293

265-
void WasmLibrary::WasmLoadImports(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* importFunctions, Var ffi)
294+
static Var GetImportVariable(Wasm::WasmImport* wi, ScriptContext* ctx, Var ffi)
295+
{
296+
PropertyRecord const * modPropertyRecord = nullptr;
297+
char16* modName = wi->modName;
298+
uint32 modNameLen = wi->modNameLen;
299+
ctx->GetOrAddPropertyRecord(modName, modNameLen, &modPropertyRecord);
300+
Var modProp = JavascriptOperators::OP_GetProperty(ffi, modPropertyRecord->GetPropertyId(), ctx);
301+
302+
303+
304+
char16* name = wi->fnName;
305+
uint32 nameLen = wi->fnNameLen;
306+
Var prop = nullptr;
307+
if (nameLen > 0)
308+
{
309+
PropertyRecord const * propertyRecord = nullptr;
310+
ctx->GetOrAddPropertyRecord(name, nameLen, &propertyRecord);
311+
312+
if (!JavascriptObject::Is(modProp))
313+
{
314+
throw Wasm::WasmCompilationException(_u("Import module %s is invalid"), modName);
315+
}
316+
prop = JavascriptOperators::OP_GetProperty(modProp, propertyRecord->GetPropertyId(), ctx);
317+
}
318+
else
319+
{
320+
// Use only first level if name is missing
321+
prop = modProp;
322+
}
323+
324+
return prop;
325+
}
326+
327+
template <typename T>
328+
void static SetGlobalValue(Var moduleEnv, uint offset, T val)
329+
{
330+
T* slot = (T*)moduleEnv + offset;
331+
*slot = val;
332+
}
333+
334+
void WasmLibrary::WasmLoadImports(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* importFunctions, Var moduleEnv, Var ffi)
266335
{
267336
const uint32 importCount = wasmModule->GetImportCount();
268337
if (importCount > 0 && (!ffi || !JavascriptObject::Is(ffi)))
@@ -271,37 +340,111 @@ namespace Js
271340
}
272341
for (uint32 i = 0; i < importCount; ++i)
273342
{
274-
PropertyRecord const * modPropertyRecord = nullptr;
275-
PropertyRecord const * propertyRecord = nullptr;
343+
Var prop = GetImportVariable(wasmModule->GetFunctionImport(i), ctx, ffi);
344+
if (!JavascriptFunction::Is(prop))
345+
{
346+
throw Wasm::WasmCompilationException(_u("Import function %s.%s is invalid"), wasmModule->GetFunctionImport(i)->modName, wasmModule->GetFunctionImport(i)->fnName);
347+
}
348+
importFunctions[i] = prop;
349+
}
350+
}
351+
352+
void WasmLibrary::WasmLoadGlobals(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var moduleEnv, Var ffi)
353+
{
354+
uint i = 0;
355+
uint count = (uint) wasmModule->globals.Count();
356+
while (i < count && wasmModule->globals.Item(i)->GetReferenceType() == Wasm::WasmGlobal::ImportedReference)
357+
{
358+
Wasm::WasmGlobal* global = wasmModule->globals.Item(i);
359+
Var prop = GetImportVariable(global->importVar, ctx, ffi);
276360

277-
char16* modName = wasmModule->GetFunctionImport(i)->modName;
278-
uint32 modNameLen = wasmModule->GetFunctionImport(i)->modNameLen;
279-
ctx->GetOrAddPropertyRecord(modName, modNameLen, &modPropertyRecord);
280-
Var modProp = JavascriptOperators::OP_GetProperty(ffi, modPropertyRecord->GetPropertyId(), ctx);
361+
uint offset = wasmModule->GetOffsetForGlobal(global);
362+
global->SetReferenceType(Wasm::WasmGlobal::Const);
281363

282-
char16* name = wasmModule->GetFunctionImport(i)->fnName;
283-
uint32 nameLen = wasmModule->GetFunctionImport(i)->fnNameLen;
284-
Var prop = nullptr;
285-
if (nameLen > 0)
364+
if (!JavascriptNumber::Is(prop) && !TaggedInt::Is(prop))
286365
{
287-
ctx->GetOrAddPropertyRecord(name, nameLen, &propertyRecord);
366+
throw Wasm::WasmCompilationException(_u("Import global %s.%s (%d) isn't a valid javascript number"), global->importVar->modName, global->importVar->fnName, i);
367+
}
288368

289-
if (!JavascriptObject::Is(modProp))
290-
{
291-
throw Wasm::WasmCompilationException(_u("Import module %s is invalid"), modName);
292-
}
293-
prop = JavascriptOperators::OP_GetProperty(modProp, propertyRecord->GetPropertyId(), ctx);
369+
switch (global->GetType())
370+
{
371+
case Wasm::WasmTypes::I32:
372+
{
373+
374+
int val = JavascriptConversion::ToInt32(prop, ctx);
375+
global->cnst.i32 = val; //resolve global to const
376+
SetGlobalValue(moduleEnv, offset, val);
377+
break;
378+
}
379+
case Wasm::WasmTypes::F32:
380+
{
381+
float val = (float) JavascriptConversion::ToNumber(prop, ctx);
382+
global->cnst.f32 = val;
383+
SetGlobalValue(moduleEnv, offset, val);
384+
}
385+
case Wasm::WasmTypes::F64:
386+
{
387+
double val = JavascriptConversion::ToNumber(prop, ctx);
388+
global->cnst.f64 = val;
389+
SetGlobalValue(moduleEnv, offset, val);
390+
break;
391+
}
392+
case Wasm::WasmTypes::I64:
393+
default:
394+
Assert(UNREACHED);
395+
break;
396+
397+
}
398+
i++;
399+
}
400+
401+
402+
for (; i < count; i++)
403+
{
404+
Wasm::WasmGlobal* global = wasmModule->globals.Item(i);
405+
406+
uint offset = wasmModule->GetOffsetForGlobal(global);
407+
Wasm::WasmGlobal* sourceGlobal = nullptr;
408+
if (global->GetReferenceType() == Wasm::WasmGlobal::Const)
409+
{
410+
sourceGlobal = global;
294411
}
295412
else
296413
{
297-
// Use only first level if name is missing
298-
prop = modProp;
414+
sourceGlobal = wasmModule->globals.Item(global->var.num);
415+
Assert(sourceGlobal->GetReferenceType() != Wasm::WasmGlobal::ImportedReference); //no imported globals at this point
416+
if (sourceGlobal->GetReferenceType() != Wasm::WasmGlobal::Const)
417+
{
418+
throw Wasm::WasmCompilationException(_u("Global %d is initialized with global %d "
419+
"which is not a const. Forward references aren't supported!"), i, global->var.num);
420+
}
421+
global->SetReferenceType(Wasm::WasmGlobal::Const); //resolve global to const
422+
global->cnst = sourceGlobal->cnst;
423+
424+
Assert(sourceGlobal->GetReferenceType() == Wasm::WasmGlobal::Const);
425+
if (sourceGlobal->GetType() != global->GetType())
426+
{
427+
throw Wasm::WasmCompilationException(_u("Type mismatch between %d and %d"), i, global->var.num);
428+
}
299429
}
300-
if (!JavascriptFunction::Is(prop))
430+
431+
switch (sourceGlobal->GetType())
301432
{
302-
throw Wasm::WasmCompilationException(_u("Import function %s.%s is invalid"), modName, name);
433+
case Wasm::WasmTypes::I32:
434+
SetGlobalValue(moduleEnv, offset, sourceGlobal->cnst.i32);
435+
break;
436+
case Wasm::WasmTypes::F32:
437+
SetGlobalValue(moduleEnv, offset, sourceGlobal->cnst.f32);
438+
break;
439+
case Wasm::WasmTypes::F64:
440+
SetGlobalValue(moduleEnv, offset, sourceGlobal->cnst.f64);
441+
break;
442+
case Wasm::WasmTypes::I64:
443+
default:
444+
Assert(UNREACHED);
445+
break;
303446
}
304-
importFunctions[i] = prop;
447+
305448
}
306449
}
307450

@@ -389,13 +532,15 @@ namespace Js
389532
exportObj = JavascriptOperators::NewJavascriptObjectNoArg(scriptContext);
390533
Var* localModuleFunctions = moduleEnvironmentPtr + wasmModule->GetFuncOffset();
391534

535+
WasmLoadGlobals(wasmModule, scriptContext, moduleEnvironmentPtr, ffi);
392536
WasmLoadDataSegs(wasmModule, heap, scriptContext);
393537

394538
bool hasAnyLazyTraps = false;
395539
WasmLoadFunctions(wasmModule, scriptContext, moduleEnvironmentPtr, &exportObj, localModuleFunctions, &hasAnyLazyTraps);
396-
540+
397541
Var* importFunctions = moduleEnvironmentPtr + wasmModule->GetImportFuncOffset();
398-
WasmLoadImports(wasmModule, scriptContext, importFunctions, ffi);
542+
WasmLoadImports(wasmModule, scriptContext, importFunctions, moduleEnvironmentPtr, ffi);
543+
399544

400545
Js::Var exportsNamespace = JavascriptOperators::NewJavascriptObjectNoArg(scriptContext);
401546
WasmBuildObject(wasmModule, scriptContext, exportsNamespace, heap, &exportObj, &hasAnyLazyTraps, localModuleFunctions, importFunctions);

lib/Runtime/Library/WasmLibrary.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ namespace Js
3333
static void WasmLoadDataSegs(Wasm::WasmModule * wasmModule, Var* heap, ScriptContext* ctx);
3434
static void WasmLoadFunctions(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* moduleMemoryPtr, Var* exportObj, Var* localModuleFunctions, bool* hasAnyLazyTraps);
3535
static void WasmBuildObject(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var exportsNamespace, Var* heap, Var* exportObj, bool* hasAnyLazyTraps, Var* localModuleFunctions, Var* importFunctions);
36-
static void WasmLoadImports(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* importFunctions, Var ffi);
36+
static void WasmLoadImports(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var* importFunctions, Var moduleEnv, Var ffi);
37+
static void WasmLoadGlobals(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var moduleEnv, Var ffi);
3738
static void WasmLoadIndirectFunctionTables(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var** indirectFunctionTables, Var* localModuleFunctions, Var* importFunctions);
3839
static Var GetFunctionObjFromFunctionIndex(Wasm::WasmModule * wasmModule, ScriptContext* ctx, uint32 funcIndex, Var* localModuleFunctions, Var* importFunctions);
3940

lib/WasmReader/Chakra.WasmReader.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@
4646
<ClCompile Include="$(MSBuildThisFileDirectory)WasmBinaryReader.cpp" />
4747
<ClCompile Include="$(MSBuildThisFileDirectory)WasmSection.cpp" />
4848
<ClCompile Include="$(MSBuildThisFileDirectory)WasmSignature.cpp" />
49+
<ClCompile Include="WasmGlobal.cpp" />
4950
</ItemGroup>
5051
<ItemGroup>
52+
<ClInclude Include="WasmGlobal.h" />
5153
<ClInclude Include="WasmModule.h" />
5254
<ClInclude Include="WasmBytecodeGenerator.h" />
5355
<ClInclude Include="WasmDataSegment.h" />

lib/WasmReader/Chakra.WasmReader.vcxproj.filters

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<ClInclude Include="WasmSections.h" />
1414
<ClInclude Include="WasmSection.h" />
1515
<ClInclude Include="WasmDataSegment.h" />
16+
<ClInclude Include="WasmGlobal.h" />
1617
</ItemGroup>
1718
<ItemGroup>
1819
<ClCompile Include="$(MSBuildThisFileDirectory)WasmModule.cpp" />
@@ -23,5 +24,6 @@
2324
<ClCompile Include="$(MSBuildThisFileDirectory)WasmSection.cpp" />
2425
<ClCompile Include="$(MSBuildThisFileDirectory)WasmSignature.cpp" />
2526
<ClCompile Include="$(MSBuildThisFileDirectory)WasmReaderPch.cpp" />
27+
<ClCompile Include="WasmGlobal.cpp" />
2628
</ItemGroup>
2729
</Project>

lib/WasmReader/WasmBinaryOpCodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ WASM_MISC_OPCODE(SetLocal, 0x15, Limit, false)
9595
WASM_MISC_OPCODE(Call, 0x16, Limit, false)
9696
WASM_MISC_OPCODE(CallIndirect, 0x17, Limit, false)
9797
WASM_MISC_OPCODE(TeeLocal, 0x19, Limit, false)
98+
WASM_MISC_OPCODE(GetGlobal, 0xbb, Limit, false)
99+
WASM_MISC_OPCODE(SetGlobal, 0xbc, Limit, false)
98100

99101
// Load memory expressions.
100102
WASM_MEMREAD_OPCODE(I32LoadMem8S, 0x20, I_I, false)

0 commit comments

Comments
 (0)