Skip to content

Commit 51ff53f

Browse files
AaronRobinsonMSFTradekdoulikpavelsavarajkotas
authored
Empty Main works for corerun on WASM (#119448)
* Implement RhpNewArrayFast, RhpNewPtrArrayFast, and RhNewString as portable (C++). * Call native fcalls * Remove unused function, Object::InitMethodTable() in native AOT. Remove finalizer clean-up triggers for WASM. * Add checks to avoid doing unnecessary work for getting a JIT helper. --------- Co-authored-by: Radek Doulik <radek.doulik@gmail.com> Co-authored-by: Pavel Savara <pavelsavara@microsoft.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent e76141c commit 51ff53f

26 files changed

+288
-128
lines changed

docs/workflow/building/coreclr/wasm.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,13 @@ This will start a local HTTP server and you can open the provided URL in your br
6363
You can also run the runtime directly in Node.js:
6464

6565
```bash
66-
cd artifacts/bin/coreclr/browser.wasm.Debug/
67-
node ./corerun.js -c /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/helloworld.dll
66+
cp /runtime3/artifacts/bin/microsoft.netcore.app.runtime.browser-wasm/Debug/runtimes/browser-wasm/lib/net10.0/*.dll /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL
67+
cp helloworld.dll /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL
68+
cd /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/
69+
node ./corerun.js -c /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL /runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/helloworld.dll
6870
```
6971

70-
Note that path in the `args` need to be absolute path on your host file system in unix format (even on Windows).
72+
Note that path in the node args need to be **absolute path** on your host file system in **unix format** (even on Windows).
7173

7274
## Debugging
7375

@@ -109,11 +111,10 @@ VS Code, through Node.js, provides a good debugging option for WebAssembly CoreC
109111
"outputCapture": "std",
110112
"program": "corerun.js",
111113
"env": {
112-
"PAL_DBG_CHANNELS": "+all.all"
114+
"PAL_DBG_CHANNELS": "+all.all",
115+
"CORE_ROOT":"/runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/"
113116
},
114117
"args": [
115-
"-c",
116-
"/runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/",
117118
"/runtime3/artifacts/bin/coreclr/browser.wasm.Debug/IL/helloworld.dll"
118119
],
119120
"cwd": "${workspaceFolder}/artifacts/bin/coreclr/browser.wasm.Debug/"
@@ -122,12 +123,14 @@ VS Code, through Node.js, provides a good debugging option for WebAssembly CoreC
122123
}
123124
```
124125

125-
Note that path in the `args` need to be absolute path on your host file system in unix format (even on Windows).
126+
Note that path in the `args` and `CORE_ROOT` need to be **absolute path** on your host file system in **unix format** (even on Windows).
126127

127-
3. **Set breakpoints** in `corewasmrun.js` in one of the `put_char` functions (the `stdout`/`stderr` implementation)
128+
3. **Copy managed DLLs** `System.Runtime.dll` and `helloworld.dll` into `artifacts/bin/coreclr/browser.wasm.Debug/IL/`.
128129

129-
4. **Start debugging** and step through the WebAssembly code using the call stack
130+
4. **Set breakpoints** in `corewasmrun.js` in one of the `put_char` functions (the `stdout`/`stderr` implementation)
131+
132+
5. **Start debugging** and step through the WebAssembly code using the call stack
130133

131134
This approach allows you to debug the JavaScript host and step into WebAssembly code or into the C/C++ code if the Dwarf Debugging extension was installed.
132135

133-
5. to display `WCHAR *` strings in debugger watch window, cast it to `char16_t*` like `(char16_t*)pLoaderModule->m_fileName`
136+
6. to display `WCHAR *` strings in debugger watch window, cast it to `char16_t*` like `(char16_t*)pLoaderModule->m_fileName`

src/coreclr/interpreter/compiler.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,13 +1093,13 @@ void InterpCompiler::BuildGCInfo(InterpMethod *pInterpMethod)
10931093
}
10941094

10951095
gcInfoEncoder->SetSizeOfStackOutgoingAndScratchArea(0);
1096-
1096+
10971097
if (m_compHnd->getMethodAttribs(m_methodInfo->ftn) & CORINFO_FLG_SHAREDINST)
10981098
{
10991099
if ((m_methodInfo->options & CORINFO_GENERICS_CTXT_MASK) != CORINFO_GENERICS_CTXT_FROM_THIS)
11001100
{
11011101
assert(paramType != GENERIC_CONTEXTPARAM_NONE);
1102-
1102+
11031103
int32_t genericArgStackOffset = m_pVars[getParamArgIndex()].offset;
11041104
INTERP_DUMP("SetGenericsInstContextStackSlot at %u\n", (unsigned)genericArgStackOffset);
11051105
gcInfoEncoder->SetPrologSize(4); // Size of 1 instruction
@@ -3016,7 +3016,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
30163016
if (iLogicalArg != 0 || !callInfo.sig.hasThis() || newObj)
30173017
{
30183018
CORINFO_CLASS_HANDLE classHandle;
3019-
3019+
30203020
// Implement the implicit argument conversion rules of III.1.6
30213021
switch (m_pStackPointer[iCurrentStackArg].type)
30223022
{
@@ -3062,7 +3062,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
30623062
break;
30633063
}
30643064
break;
3065-
// TODO-Interp, for 64bit Big endian platforms, we may need to implement the
3065+
// TODO-Interp, for 64bit Big endian platforms, we may need to implement the
30663066
// truncation rules for NativeInt/NativeUInt to I4/U4. However, on little-endian
30673067
// platforms, the interpreter calling convention will naturally produce the
30683068
// truncation, so there is no additional code necessary.

src/coreclr/nativeaot/Runtime/GCHelpers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,11 +617,11 @@ static Object* GcAllocInternal(MethodTable* pEEType, uint32_t uFlags, uintptr_t
617617
if (pObject == NULL)
618618
return NULL;
619619

620-
pObject->set_EEType(pEEType);
620+
pObject->SetMethodTable(pEEType);
621621
if (pEEType->HasComponentSize())
622622
{
623623
ASSERT(numElements == (uint32_t)numElements);
624-
((Array*)pObject)->InitArrayLength((uint32_t)numElements);
624+
((Array*)pObject)->SetNumComponents((uint32_t)numElements);
625625
}
626626

627627
if (isSampled)

src/coreclr/nativeaot/Runtime/ObjectLayout.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@
1616
#include "ObjectLayout.h"
1717
#include "MethodTable.inl"
1818

19-
#ifndef DACCESS_COMPILE
20-
void Object::InitEEType(MethodTable * pEEType)
21-
{
22-
ASSERT(NULL == m_pEEType);
23-
m_pEEType = pEEType;
24-
}
25-
#endif
26-
2719
uint32_t Array::GetArrayLength()
2820
{
2921
return m_Length;
@@ -37,7 +29,7 @@ void* Array::GetArrayData()
3729
}
3830

3931
#ifndef DACCESS_COMPILE
40-
void Array::InitArrayLength(uint32_t length)
32+
void Array::SetNumComponents(uint32_t length)
4133
{
4234
m_Length = length;
4335
}

src/coreclr/nativeaot/Runtime/ObjectLayout.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ class Object
5252
#endif
5353
ObjHeader * GetHeader() { return dac_cast<DPTR(ObjHeader)>(dac_cast<TADDR>(this) - SYNC_BLOCK_SKEW); }
5454
#ifndef DACCESS_COMPILE
55-
void set_EEType(MethodTable * pEEType)
55+
void SetMethodTable(MethodTable * pEEType)
5656
{ m_pEEType = pEEType; }
57-
void InitEEType(MethodTable * pEEType);
5857

5958
size_t GetSize();
6059
#endif
@@ -85,16 +84,16 @@ static uintptr_t const REFERENCE_SIZE = sizeof(Object *);
8584
//-------------------------------------------------------------------------------------------------
8685
class Array : public Object
8786
{
88-
friend class ArrayBase;
8987
friend class AsmOffsets;
9088

89+
protected:
9190
uint32_t m_Length;
9291
#if defined(HOST_64BIT)
9392
uint32_t m_uAlignpad;
9493
#endif // HOST_64BIT
9594
public:
9695
uint32_t GetArrayLength();
97-
void InitArrayLength(uint32_t length);
96+
void SetNumComponents(uint32_t length);
9897
void* GetArrayData();
9998
};
10099
typedef DPTR(Array) PTR_Array;

src/coreclr/nativeaot/Runtime/portable.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ FCIMPL1(Object *, RhpNewFast, MethodTable* pEEType)
6969
{
7070
acontext->alloc_ptr = alloc_ptr + size;
7171
Object* pObject = (Object *)alloc_ptr;
72-
pObject->set_EEType(pEEType);
72+
pObject->SetMethodTable(pEEType);
7373
return pObject;
7474
}
7575

@@ -118,8 +118,8 @@ FCIMPL2(Array *, RhpNewArrayFast, MethodTable * pArrayEEType, int numElements)
118118
{
119119
acontext->alloc_ptr = alloc_ptr + size;
120120
Array* pObject = (Array*)alloc_ptr;
121-
pObject->set_EEType(pArrayEEType);
122-
pObject->InitArrayLength((uint32_t)numElements);
121+
pObject->SetMethodTable(pArrayEEType);
122+
pObject->SetNumComponents((uint32_t)numElements);
123123
return pObject;
124124
}
125125

@@ -174,11 +174,11 @@ FCIMPL1(Object*, RhpNewFastAlign8, MethodTable* pEEType)
174174
if (requiresPadding)
175175
{
176176
Object* dummy = (Object*)alloc_ptr;
177-
dummy->set_EEType(g_pFreeObjectEEType);
177+
dummy->SetMethodTable(g_pFreeObjectEEType);
178178
alloc_ptr += 12;
179179
}
180180
Object* pObject = (Object *)alloc_ptr;
181-
pObject->set_EEType(pEEType);
181+
pObject->SetMethodTable(pEEType);
182182
return pObject;
183183
}
184184

@@ -209,11 +209,11 @@ FCIMPL1(Object*, RhpNewFastMisalign, MethodTable* pEEType)
209209
if (requiresPadding)
210210
{
211211
Object* dummy = (Object*)alloc_ptr;
212-
dummy->set_EEType(g_pFreeObjectEEType);
212+
dummy->SetMethodTable(g_pFreeObjectEEType);
213213
alloc_ptr += 12;
214214
}
215215
Object* pObject = (Object *)alloc_ptr;
216-
pObject->set_EEType(pEEType);
216+
pObject->SetMethodTable(pEEType);
217217
return pObject;
218218
}
219219

@@ -259,12 +259,12 @@ FCIMPL2(Array*, RhpNewArrayFastAlign8, MethodTable* pArrayEEType, int numElement
259259
if (requiresAlignObject)
260260
{
261261
Object* dummy = (Object*)alloc_ptr;
262-
dummy->set_EEType(g_pFreeObjectEEType);
262+
dummy->SetMethodTable(g_pFreeObjectEEType);
263263
alloc_ptr += 12;
264264
}
265265
Array* pObject = (Array*)alloc_ptr;
266-
pObject->set_EEType(pArrayEEType);
267-
pObject->InitArrayLength((uint32_t)numElements);
266+
pObject->SetMethodTable(pArrayEEType);
267+
pObject->SetNumComponents((uint32_t)numElements);
268268
return pObject;
269269
}
270270

src/coreclr/runtime/portable/AllocFast.cpp

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,65 @@
44

55
#include <fcall.h>
66

7+
extern void RhExceptionHandling_FailedAllocation(MethodTable *pMT, bool isOverflow);
8+
79
EXTERN_C FCDECL2(Object*, RhpNewVariableSizeObject, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
810
{
911
PORTABILITY_ASSERT("RhpNewVariableSizeObject is not yet implemented");
1012
return nullptr;
1113
}
1214

15+
static Object* _RhpNewArrayFastCore(CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
16+
{
17+
FCALL_CONTRACT;
18+
_ASSERTE(typeHnd_ != NULL);
19+
_ASSERTE(size < INT32_MAX);
20+
21+
MethodTable* pMT = (MethodTable*)typeHnd_;
22+
Thread* thread = GetThread();
23+
ee_alloc_context* cxt = thread->GetEEAllocContext();
24+
25+
size_t sizeInBytes = (size_t)pMT->GetBaseSize() + ((size_t)size * (size_t)pMT->RawGetComponentSize());
26+
sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*));
27+
28+
uint8_t* alloc_ptr = cxt->getAllocPtr();
29+
ASSERT(alloc_ptr <= cxt->getAllocLimit());
30+
if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes)
31+
{
32+
cxt->setAllocPtr(alloc_ptr + sizeInBytes);
33+
PtrArray* pObject = (PtrArray *)alloc_ptr;
34+
pObject->SetMethodTable(pMT);
35+
pObject->SetNumComponents((INT32)size);
36+
return pObject;
37+
}
38+
39+
return RhpNewVariableSizeObject(typeHnd_, size);
40+
}
41+
1342
EXTERN_C FCDECL2(Object*, RhpNewArrayFast, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
1443
{
15-
PORTABILITY_ASSERT("RhpNewArrayFast is not yet implemented");
16-
return nullptr;
44+
FCALL_CONTRACT;
45+
_ASSERTE(typeHnd_ != NULL);
46+
47+
MethodTable* pMT = (MethodTable*)typeHnd_;
48+
49+
#ifndef HOST_64BIT
50+
// if the element count is <= 0x10000, no overflow is possible because the component size is
51+
// <= 0xffff, and thus the product is <= 0xffff0000, and the base size is only ~12 bytes
52+
if (size > 0x10000)
53+
{
54+
// Overflow here should result in an OOM. Let the slow path take care of it.
55+
return RhpNewVariableSizeObject(typeHnd_, size);
56+
}
57+
#endif // !HOST_64BIT
58+
59+
return _RhpNewArrayFastCore(typeHnd_, size);
1760
}
1861

1962
EXTERN_C FCDECL2(Object*, RhpNewPtrArrayFast, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size)
2063
{
21-
PORTABILITY_ASSERT("RhpNewPtrArrayFast is not yet implemented");
22-
return nullptr;
64+
WRAPPER_NO_CONTRACT;
65+
return RhpNewArrayFast(typeHnd_, size);
2366
}
2467

2568
EXTERN_C FCDECL1(Object*, RhpNewFast, CORINFO_CLASS_HANDLE typeHnd_)
@@ -46,8 +89,20 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, CORINFO_CLASS_HANDLE typeHnd_)
4689
return nullptr;
4790
}
4891

92+
#define MAX_STRING_LENGTH 0x3FFFFFDF
93+
4994
EXTERN_C FCDECL2(Object*, RhNewString, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR stringLength)
5095
{
51-
PORTABILITY_ASSERT("RhNewString is not yet implemented");
52-
return nullptr;
96+
FCALL_CONTRACT;
97+
_ASSERTE(typeHnd_ != NULL);
98+
99+
MethodTable* pMT = (MethodTable*)typeHnd_;
100+
101+
if (stringLength > MAX_STRING_LENGTH)
102+
{
103+
RhExceptionHandling_FailedAllocation(pMT, false);
104+
return NULL;
105+
}
106+
107+
return _RhpNewArrayFastCore(typeHnd_, stringLength);
53108
}

src/coreclr/vm/callstubgenerator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ CallStubHeader *CallStubGenerator::GenerateCallStubForSig(MetaSig &sig)
13531353
// Allocate space for the routines. The size of the array is conservatively set to twice the number of arguments
13541354
// plus one slot for the target pointer and reallocated to the real size at the end.
13551355
size_t tempStorageSize = ComputeTempStorageSize(sig);
1356-
PCODE *pRoutines = (PCODE*)alloca(ComputeTempStorageSize(sig));
1356+
PCODE *pRoutines = (PCODE*)alloca(tempStorageSize);
13571357
memset(pRoutines, 0, tempStorageSize);
13581358

13591359
m_interpreterToNative = true; // We always generate the interpreter to native call stub here

0 commit comments

Comments
 (0)