Repository: pyodide/pyodide
Pull request: Remove function pointer cast emulation
This is a third attempt at the fpcast removal. The good news is that chrome is working okay here.

I guess this one works.

Closes #2016. Closes #1677. Closes #1577.

Problem statement:
fpcast emulation tracing and removing
We currently build with function pointer cast emulation. It is really hard to remove this because it is hard to know where bad function calls are being made (i.e. where an indirect call is made where the call arguments don't match the target function arguments).

I would suggest that what is needed is some kind of fpcast_emulation with tracing build, then run the full test suite on that, hopefully it would hit the majority of the function pointer casting shenanigans. In theory this was fixed in python in 3.8, so we should be good with core python, but we do bundle some other stuff for images and fonts etc. that might cause issues. The patches to scipy/numpy removed most issues there too, but there may be some that I missed. 

I suspect the easiest way to do this is to make a build which in emscripten replaces indirect calls to a call to a python indirect call trampoline, so that rather than call to fpcast versions, it calls to something in imports which is javascript and does the actual call. I think that side of things would need a change to visitCallIndirect in the binaryen pass to just make it call the javascript trampoline with the signature of the indirect call as a parameter. Then the fpcast trampoline could check that against the signature of what it was calling (using the same , and chuck out a log message if they didn't match. This would be way more efficient if webassembly type reflection was enabled otherwise some manual type reflection cunningness would be needed to get the type of the target. Type reflection is behind a flag in chromium (enable experimental webassembly features). 

I imagine it would be slow as a slow thing, but for testing it would do the job I imagine.

I would suggest it isn't much work to update binaryen to call the trampoline, then creating a build that works in chromium with webassembly reflection enabled. It might be that if one can get pyodide itself loading in chromium and run the test suite, that is enough to exercise the code enough to find out what is the cause of the naughty pointer calls and sort it.

I won't have time to do anything till teaching and marking ends (i.e. june/july at earliest), but if anyone wants to do it, I'm happy to input.

Hints from issue discussion:
Thanks for opening this issue with a detailed plan @joemarshall !

Personally I also won't have much availability to look into this in the near future, but I very much look forward to getting rid of fpcast emulation. It should also help for Python performance #1120  as far as I understand.
I had a tiny fiddle with this - interestingly pyodide itself now loads, I can run code in the JS console before the python console.html loads, but I can't run anything in the console without hitting a failure somewhere in jsproxy.

Latest chrome canary plus webassembly debugging however means that
a) you get the exception about null pointer or wrong pointer type
b) you actually can get the code lines and stuff that is failing in the C code now. 

Something is broken in python waiting for js promises. I'll have a peek at how that works.

Good news is that it is now debuggable without having to do the logging thing...
Aha, python core seems to mostly work nowadays, but in jsproxy / asyncio it breaks, calling asyncio.ensure_future on a javascript promise doesn't work and causes a crash that I will describe below:

Firstly, a fail case - if I stick this in javascript console, I can reproduce it without having to step through shed loads of console stuff. Just load console.html as normal, then run this in the js console before you type anything in the web page. I think something in jsproxy has the wrong function signature.

```
p=Promise.resolve('Great')
pyodide.runPython('import js,asyncio\nprint(js.p)\nasyncio.ensure_future(js.p)\n')
```

```
Uncaught RuntimeError: null function or function signature mismatch
    at wrap_unaryfunc (typeobject.c:5661)
    at wrapperdescr_raw_call (descrobject.c:483)
    at wrapper_call (descrobject.c:1303)
    at _PyObject_MakeTpCall (call.c:159)
    at _PyObject_Vectorcall (abstract.h:125)
    at call_function (ceval.c:4999)
    at _PyEval_EvalFrameDefault (ceval.c:3475)
    at PyEval_EvalFrameEx (ceval.c:741)
    at gen_send_ex (genobject.c:222)
    at _PyGen_Send (genobject.c:292)
```


Running a python trace (see below), it is hitting the failure within the python code here:
https://github.com/python/cpython/blob/v3.8.2/Lib/asyncio/tasks.py#L684


```
pyodide.runPython("import sys\ndef tf(a,b,c):\n  print(a,b,c)\n  return tf\nsys.settrace(tf)\n")
```

```
<frame at 0xc75100, file '/lib/python3.8/asyncio/events.py', line 79, code _run> call None
pyodide.asm.js:3708 <frame at 0xc75100, file '/lib/python3.8/asyncio/events.py', line 80, code _run> line None
pyodide.asm.js:3708 <frame at 0xc75100, file '/lib/python3.8/asyncio/events.py', line 81, code _run> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 263, code __step> call None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 264, code __step> line None
pyodide.asm.js:3708 <frame at 0xca00f0, file '/lib/python3.8/asyncio/futures.py', line 157, code done> call None
pyodide.asm.js:3708 <frame at 0xca00f0, file '/lib/python3.8/asyncio/futures.py', line 163, code done> line None
pyodide.asm.js:3708 <frame at 0xca00f0, file '/lib/python3.8/asyncio/futures.py', line 163, code done> return False
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 267, code __step> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 271, code __step> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 272, code __step> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 274, code __step> line None
pyodide.asm.js:3708 <frame at 0xc75280, file '/lib/python3.8/asyncio/tasks.py', line 929, code _enter_task> call None
pyodide.asm.js:3708 <frame at 0xc75280, file '/lib/python3.8/asyncio/tasks.py', line 930, code _enter_task> line None
pyodide.asm.js:3708 <frame at 0xc75280, file '/lib/python3.8/asyncio/tasks.py', line 931, code _enter_task> line None
pyodide.asm.js:3708 <frame at 0xc75280, file '/lib/python3.8/asyncio/tasks.py', line 934, code _enter_task> line None
pyodide.asm.js:3708 <frame at 0xc75280, file '/lib/python3.8/asyncio/tasks.py', line 934, code _enter_task> return None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 276, code __step> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 277, code __step> line None
pyodide.asm.js:3708 <frame at 0xc9f3e8, file '/lib/python3.8/asyncio/tasks.py', line 280, code __step> line None
pyodide.asm.js:3708 <frame at 0x89f358, file '/lib/python3.8/asyncio/tasks.py', line 677, code _wrap_awaitable> call None
pyodide.asm.js:3708 <frame at 0x89f358, file '/lib/python3.8/asyncio/tasks.py', line 684, code _wrap_awaitable> line None
```
Aha,

```
slots[cur_slot++] =
      (PyType_Slot){ .slot = Py_am_await, .pfunc = (void*)JsProxy_Await };
```
but JsProxy_Await needs to be a unaryfunction to go in the Py_am_await typeslot

https://docs.python.org/3/c-api/typeobj.html#c.unaryfunc

It doesn't use args, so maybe just a typo.
oh yeah, core python works (or at least the console appears to run okay) if I fix that, even with fpcast turned off! That's cool.
That great news! cc @hoodmane regarding the `JsProxy_Await` function signature.

Does it mean that we could be build CPython at least without `EMULATE_FUNCTION_POINTER_CASTS` or do we need to build all either with or without?
We need to build everything with or without. Bad things will happen otherwise.

There's also a patch needed in cpython with dictionaries which makes the tests fail right now. Can't reverse the items or values in a dictionary, there are casts in dictobject between for a function taking one parameter to a pycfunction which should take two args and ignore the last. It is fixed for reversing the dict keys, but not for the items. Needs fixing in upstream python too.
> Needs fixing in upstream python too.

Hmm, this might be a good occasion to migrate to Python 3.9 as well https://github.com/pyodide/pyodide/issues/978.
> It doesn't use args, so maybe just a typo.

I got confused because `METH_NOARGS` functions are supposed to take an argument that they ignore.
Yeah, that's the same issue in cpython dict. I've pushed that fix to python core (https://bugs.python.org/issue44114), and it is going to be backported to 3.9 but not 3.8, so will still need a patch in pyodide until it works with 3.9. Tests for core python pass with this patch.

Still crashes on import of quite a few packages though. There are a bunch of similar errors in some of the C packages. They're quite easy to find, but it is going to be a bit whack-a-mole to find them all. Numpy for example has some multiarray getters which ignore extra void* parameters.

Incidentally, I think there would be value in trying to get cpython maintainers to add CI for webassembly into core cpython testing, so that core python at least doesn't rely on undefined c behaviour. I don't know how one does that though, I only know how to push little patches to python.

Commit message: Remove max-func-params ldflag, doesn't do anything without fpcast

Patch to review:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index d7d9e8dc3f0..2e43c6add44 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -236,16 +236,6 @@ jobs:
           command: |
             pytest -s benchmark/stack_usage.py  | sed -n 's/## //pg'
 
-  test-emsdk:
-    <<: *defaults
-    resource_class: small
-    steps:
-      - attach_workspace:
-          at: .
-      - run:
-          name: test
-          command: make -C emsdk test
-
   test-python:
     # Unlike test-main this uses "resource_class small" and doesn't use "pytest_wrapper."
     <<: *defaults
@@ -478,13 +468,6 @@ workflows:
             tags:
               only: /.*/
 
-      - test-emsdk:
-          requires:
-            - build-core
-          filters:
-            tags:
-              only: /.*/
-
       - test-js:
           requires:
             - build-core
@@ -512,7 +495,6 @@ workflows:
             - test-python
             - test-core-firefox
             - test-packages-firefox
-            - test-emsdk
           filters:
             branches:
               ignore: /.*/
@@ -524,7 +506,6 @@ workflows:
             - test-python
             - test-core-firefox
             - test-packages-firefox
-            - test-emsdk
           filters:
             branches:
               only: main
diff --git a/Makefile.envs b/Makefile.envs
index df45bd469b1..1e6cfa682d4 100644
--- a/Makefile.envs
+++ b/Makefile.envs
@@ -1,6 +1,5 @@
 export PYVERSION ?= 3.9.5
 export PYODIDE_EMSCRIPTEN_VERSION ?= 2.0.16
-export PYODIDE_BINARYEN_VERSION ?= version_100
 
 # BASH_ENV tells bash to run pyodide_env.sh on startup, whcih sets various
 # environment variables. The next line instructs make to use bash to run each
@@ -38,10 +37,8 @@ export CFLAGS_BASE=\
 	$(EXTRA_CFLAGS)
 
 export LDFLAGS_BASE=\
-	-s BINARYEN_EXTRA_PASSES="--pass-arg=max-func-params@61" \
 	$(OPTFLAGS) \
 	-s MODULARIZE=1 \
-	-s EMULATE_FUNCTION_POINTER_CASTS=1 \
 	-s LINKABLE=1 \
 	-s EXPORT_ALL=1 \
 	-s WASM=1 \
diff --git a/cpython/Makefile b/cpython/Makefile
index 882583f5e02..cbdd45faa44 100644
--- a/cpython/Makefile
+++ b/cpython/Makefile
@@ -120,7 +120,7 @@ $(INSTALL)/lib/libffi.a :
 	rm -rf $(FFIBUILD)
 	git clone $(LIBFFIREPO) $(FFIBUILD) --shallow-exclude upstream-base
 	source $(PYODIDE_ROOT)/emsdk/emsdk/emsdk_env.sh
-	cd $(FFIBUILD) && git checkout $(LIBFFI_COMMIT) && ./build.sh --pyodide-fpcast && make install
+	cd $(FFIBUILD) && git checkout $(LIBFFI_COMMIT) && ./build.sh && make install
 	cp $(FFIBUILD)/target/include/*.h $(BUILD)/Include/
 	mkdir -p $(INSTALL)/lib
 	cp $(FFIBUILD)/target/lib/libffi.a $(INSTALL)/lib/
diff --git a/cpython/patches/0001-call-trampolines-to-handle-fpcast-troubles.patch b/cpython/patches/0001-call-trampolines-to-handle-fpcast-troubles.patch
new file mode 100644
index 00000000000..6bcf0c3788f
--- /dev/null
+++ b/cpython/patches/0001-call-trampolines-to-handle-fpcast-troubles.patch
@@ -0,0 +1,179 @@
+From a608eb640f151f08ffd810e53eb29f58ef68f493 Mon Sep 17 00:00:00 2001
+From: Hood Chatham <roberthoodchatham@gmail.com>
+Date: Fri, 3 Dec 2021 20:55:40 -0800
+Subject: [PATCH] call trampolines to handle fpcast troubles
+
+---
+ Objects/call.c         |  5 ++++-
+ Objects/descrobject.c  | 28 +++++++++++++++++++---------
+ Objects/methodobject.c | 12 +++++++++---
+ 3 files changed, 32 insertions(+), 13 deletions(-)
+
+diff --git a/Objects/call.c b/Objects/call.c
+index 87dc0dbbdb..f8c7811521 100644
+--- a/Objects/call.c
++++ b/Objects/call.c
+@@ -143,6 +143,9 @@ PyObject_VectorcallDict(PyObject *callable, PyObject *const *args,
+ }
+ 
+ 
++// Defined in methodobject patch
++PyObject* method_call_trampoline(PyCFunction func, PyObject *self, PyObject *arg1, PyObject *arg2);
++
+ PyObject *
+ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
+                      PyObject *const *args, Py_ssize_t nargs,
+@@ -188,7 +191,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
+     PyObject *result = NULL;
+     if (_Py_EnterRecursiveCall(tstate, " while calling a Python object") == 0)
+     {
+-        result = call(callable, argstuple, kwdict);
++        result = method_call_trampoline((PyCFunction)call, callable, argstuple, kwdict);
+         _Py_LeaveRecursiveCall(tstate);
+     }
+ 
+diff --git a/Objects/descrobject.c b/Objects/descrobject.c
+index fce9cdd309..326844f569 100644
+--- a/Objects/descrobject.c
++++ b/Objects/descrobject.c
+@@ -174,6 +174,11 @@ member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
+     return PyMember_GetOne((char *)obj, descr->d_member);
+ }
+ 
++#include <emscripten.h>
++EM_JS(PyObject*, getter_call_trampoline, (getter get, PyObject *obj, void *closure), {
++    return wasmTable.get(get)(obj, closure);
++});
++
+ static PyObject *
+ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
+ {
+@@ -182,7 +187,7 @@ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
+     if (descr_check((PyDescrObject *)descr, obj, &res))
+         return res;
+     if (descr->d_getset->get != NULL)
+-        return descr->d_getset->get(obj, descr->d_getset->closure);
++        return getter_call_trampoline(descr->d_getset->get, obj, descr->d_getset->closure);
+     PyErr_Format(PyExc_AttributeError,
+                  "attribute '%V' of '%.100s' objects is not readable",
+                  descr_name((PyDescrObject *)descr), "?",
+@@ -228,6 +233,10 @@ member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
+     return PyMember_SetOne((char *)obj, descr->d_member, value);
+ }
+ 
++EM_JS(PyObject*, setter_call_trampoline, (setter set, PyObject *obj, PyObject *value, void *closure), {
++    return wasmTable.get(set)(obj, value, closure);
++});
++
+ static int
+ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
+ {
+@@ -236,8 +245,7 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
+     if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
+         return res;
+     if (descr->d_getset->set != NULL)
+-        return descr->d_getset->set(obj, value,
+-                                    descr->d_getset->closure);
++        return setter_call_trampoline(descr->d_getset->set, obj, value, descr->d_getset->closure);
+     PyErr_Format(PyExc_AttributeError,
+                  "attribute '%V' of '%.100s' objects is not writable",
+                  descr_name((PyDescrObject *)descr), "?",
+@@ -291,6 +299,9 @@ method_enter_call(PyThreadState *tstate, PyObject *func)
+     return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
+ }
+ 
++// Defined in methodobject patch
++PyObject* method_call_trampoline(PyCFunction func, PyObject *self, PyObject *arg1, PyObject *arg2);
++
+ /* Now the actual vectorcall functions */
+ static PyObject *
+ method_vectorcall_VARARGS(
+@@ -310,7 +321,7 @@ method_vectorcall_VARARGS(
+         Py_DECREF(argstuple);
+         return NULL;
+     }
+-    PyObject *result = meth(args[0], argstuple);
++    PyObject *result = method_call_trampoline(meth, args[0], argstuple, NULL);
+     Py_DECREF(argstuple);
+     _Py_LeaveRecursiveCall(tstate);
+     return result;
+@@ -338,12 +349,11 @@ method_vectorcall_VARARGS_KEYWORDS(
+             goto exit;
+         }
+     }
+-    PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
+-                                   method_enter_call(tstate, func);
++    PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
+     if (meth == NULL) {
+         goto exit;
+     }
+-    result = meth(args[0], argstuple, kwdict);
++    result = method_call_trampoline(meth, args[0], argstuple, kwdict);
+     _Py_LeaveRecursiveCall(tstate);
+ exit:
+     Py_DECREF(argstuple);
+@@ -431,7 +441,7 @@ method_vectorcall_NOARGS(
+     if (meth == NULL) {
+         return NULL;
+     }
+-    PyObject *result = meth(args[0], NULL);
++    PyObject *result = method_call_trampoline(meth, args[0], NULL, NULL);
+     _Py_LeaveRecursiveCall(tstate);
+     return result;
+ }
+@@ -459,7 +469,7 @@ method_vectorcall_O(
+     if (meth == NULL) {
+         return NULL;
+     }
+-    PyObject *result = meth(args[0], args[1]);
++    PyObject *result = method_call_trampoline(meth, args[0], args[1], NULL);
+     _Py_LeaveRecursiveCall(tstate);
+     return result;
+ }
+diff --git a/Objects/methodobject.c b/Objects/methodobject.c
+index 7b430416c5..b57d7a37b2 100644
+--- a/Objects/methodobject.c
++++ b/Objects/methodobject.c
+@@ -460,6 +460,12 @@ cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD(
+     return result;
+ }
+ 
++#include <emscripten.h>
++
++EM_JS(PyObject*, method_call_trampoline, (PyCFunction func, PyObject *self, PyObject *arg1, PyObject *arg2), {
++    return wasmTable.get(func)(self, arg1, arg2);
++});
++
+ static PyObject *
+ cfunction_vectorcall_NOARGS(
+     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
+@@ -482,7 +488,7 @@ cfunction_vectorcall_NOARGS(
+     if (meth == NULL) {
+         return NULL;
+     }
+-    PyObject *result = meth(PyCFunction_GET_SELF(func), NULL);
++    PyObject *result = method_call_trampoline(meth, PyCFunction_GET_SELF(func), NULL, NULL);
+     _Py_LeaveRecursiveCall(tstate);
+     return result;
+ }
+@@ -536,7 +542,7 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
+ 
+     PyObject *result;
+     if (flags & METH_KEYWORDS) {
+-        result = (*(PyCFunctionWithKeywords)(void(*)(void))meth)(self, args, kwargs);
++        result = method_call_trampoline(meth, self, args, kwargs);
+     }
+     else {
+         if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
+@@ -545,7 +551,7 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
+                           ((PyCFunctionObject*)func)->m_ml->ml_name);
+             return NULL;
+         }
+-        result = meth(self, args);
++        result = method_call_trampoline(meth, self, args, NULL);
+     }
+     return _Py_CheckFunctionResult(tstate, func, result, NULL);
+ }
+-- 
+2.25.1
+
diff --git a/cpython/patches/0008-fix-dict.patch b/cpython/patches/0008-fix-dict.patch
deleted file mode 100644
index f9a5c2c2960..00000000000
--- a/cpython/patches/0008-fix-dict.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-Fix incorrect dictkeys_reversed and dictitems_reversed function signatures in C
-https://bugs.python.org/issue44114. This patch is no longer necessary for Python 3.9.6
-
-diff --git a/Objects/dictobject.c b/Objects/dictobject.c
-index 3c56f4a..59e48a6 100644
---- a/Objects/dictobject.c
-+++ b/Objects/dictobject.c
-@@ -4433,7 +4433,7 @@ static PySequenceMethods dictitems_as_sequence = {
-     (objobjproc)dictitems_contains,     /* sq_contains */
- };
- 
--static PyObject* dictitems_reversed(_PyDictViewObject *dv);
-+static PyObject* dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
- 
- PyDoc_STRVAR(reversed_items_doc,
- "Return a reverse iterator over the dict items.");
-@@ -4486,7 +4486,7 @@ dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
- }
- 
- static PyObject *
--dictitems_reversed(_PyDictViewObject *dv)
-+dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
- {
-     if (dv->dv_dict == NULL) {
-         Py_RETURN_NONE;
-@@ -4516,7 +4516,7 @@ static PySequenceMethods dictvalues_as_sequence = {
-     (objobjproc)0,                      /* sq_contains */
- };
- 
--static PyObject* dictvalues_reversed(_PyDictViewObject *dv);
-+static PyObject* dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
- 
- PyDoc_STRVAR(reversed_values_doc,
- "Return a reverse iterator over the dict values.");
-@@ -4567,7 +4567,7 @@ dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
- }
- 
- static PyObject *
--dictvalues_reversed(_PyDictViewObject *dv)
-+dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
- {
-     if (dv->dv_dict == NULL) {
-         Py_RETURN_NONE;
diff --git a/cpython/patches/avoid-fpcalls-in-CALL_FUNCTION.patch b/cpython/patches/avoid-fpcalls-in-CALL_FUNCTION.patch
deleted file mode 100644
index b1848a2a206..00000000000
--- a/cpython/patches/avoid-fpcalls-in-CALL_FUNCTION.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 6933302eebb82b4a7839070963cb338ed92a234b Mon Sep 17 00:00:00 2001
-From: Hood <hood@mit.edu>
-Date: Wed, 7 Jul 2021 09:24:48 -0700
-Subject: [PATCH] Remove byn$fpcast calls from CALL_FUNCTION implementation
-
-The goal of this patch is to avoid making the two byn$fpcast calls in the Python
-CALL_FUNCTION instruction. These calls take up a ton of stack space and are also
-slow. 
-
-We hard code _PyEval_EvalFrame to call _PyEval_EvalFrameDefault rather than
-calling tstate->interp->eval_frame (existing Python JITs will not work with
-Pyodide anyways).
-
-In implementation of `PyObject_Vectorcall` we check explicitly if
-`pyobj->tp_vectorcall == _PyFunction_Vectorcall` (this is the case for normal
-Python functions). In this case we can avoid calling the function pointer.
-
-
----
- Include/cpython/abstract.h      | 6 +++++-
- Include/internal/pycore_ceval.h | 2 +-
- 2 files changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
-index 0f1304d..9cb1286 100644
---- a/Include/cpython/abstract.h
-+++ b/Include/cpython/abstract.h
-@@ -115,7 +115,11 @@ _PyObject_VectorcallTstate(PyThreadState *tstate, PyObject *callable,
-         Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
-         return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwnames);
-     }
--    res = func(callable, args, nargsf, kwnames);
-+    if(func == _PyFunction_Vectorcall){
-+        res = _PyFunction_Vectorcall(callable, args, nargsf, kwnames);
-+    } else {
-+        res = func(callable, args, nargsf, kwnames);
-+    }
-     return _Py_CheckFunctionResult(tstate, callable, res, NULL);
- }
- 
-diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
-index 18c8f02..ddb3d22 100644
---- a/Include/internal/pycore_ceval.h
-+++ b/Include/internal/pycore_ceval.h
-@@ -37,7 +37,7 @@ void _PyEval_Fini(void);
- static inline PyObject*
- _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
- {
--    return tstate->interp->eval_frame(tstate, f, throwflag);
-+    return _PyEval_EvalFrameDefault(tstate, f, throwflag);
- }
- 
- extern PyObject *_PyEval_EvalCode(
--- 
-2.17.1
-
diff --git a/emsdk/Makefile b/emsdk/Makefile
index 52b6494bc76..d0944b82202 100644
--- a/emsdk/Makefile
+++ b/emsdk/Makefile
@@ -6,19 +6,11 @@ all: emsdk/.complete
 emsdk/.complete: ../Makefile.envs $(wildcard patches/*.patch)
 	if [ -d emsdk ]; then rm -rf emsdk; fi
 	git clone --depth 1 https://github.com/emscripten-core/emsdk.git
-	git clone -b $(PYODIDE_BINARYEN_VERSION) --depth 1 https://github.com/WebAssembly/binaryen.git emsdk/binaryen
 	cd emsdk && ./emsdk install --build=Release $(PYODIDE_EMSCRIPTEN_VERSION)
 	cat patches/*.patch | patch -p1
 	cd emsdk && ./emsdk install --build=Release $(PYODIDE_EMSCRIPTEN_VERSION) ccache-git-emscripten-64bit
 	cd emsdk && ./emsdk activate --embedded --build=Release $(PYODIDE_EMSCRIPTEN_VERSION)
-	cd emsdk/binaryen && cmake -DBUILD_STATIC_LIB=ON -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
-	make -C emsdk/binaryen -j5 wasm-opt
-	cp emsdk/binaryen/bin/wasm-opt emsdk/upstream/bin/
 	touch emsdk/.complete
 
-.PHONY: test
-test:
-	pytest tests/ -v
-
 clean:
 	rm -rf emsdk
diff --git a/emsdk/patches/fix_emscripten_dylink.patch b/emsdk/patches/fix_emscripten_dylink.patch
deleted file mode 100644
index bbd8b76b478..00000000000
--- a/emsdk/patches/fix_emscripten_dylink.patch
+++ /dev/null
@@ -1,171 +0,0 @@
-diff --git a/emsdk/upstream/emscripten/src/library.js b/emsdk/upstream/emscripten/src/library.js
-index 2990646..517fc33 100644
-@@ -3749,6 +3749,15 @@ LibraryManager.library = {
- #endif
- #if ASSERTIONS
-     assert(wasmTable.get(ptr), 'missing table entry in dynCall: ' + ptr);
-+#endif
-+#if EMULATE_FUNCTION_POINTER_CASTS
-+    if( ptr in dyncallInvokeMap)
-+    {
-+        // in fpcast mode, we use a separate table or else we'll attempt
-+        // to call the fpcast emulated version which is not what the linker
-+        // expects for a linked dynamic call
-+        ptr=dyncallInvokeMap[ptr];
-+    }
- #endif
-     return wasmTable.get(ptr).apply(null, args)
- #endif
---- a/emsdk/upstream/emscripten/src/runtime_init_table.js
-+++ b/emsdk/upstream/emscripten/src/runtime_init_table.js
-@@ -13,3 +13,17 @@ var wasmTable = new WebAssembly.Table({
- // the exports are available.
- var wasmTable;
- #endif
-+#if EMULATE_FUNCTION_POINTER_CASTS==1
-+    // when we call dynamic link functions through the relocation
-+    // invoke xxx methods, we aren't doing a function pointer
-+    // call, so we don't mess with the function prototype.
-+    // however, we do need to make the function table
-+    // point to the emulated bny$fpcast-emu$ function pointer calls or else you
-+    // can't take function pointers in wasm code.
-+    // this means we need a different table for javascript dyncall invokes
-+    // as given these are pre-linked and don't use function pointer casts, they
-+    // will use the non-emulated version with the normal arguments.
-+    // nb. this doesn't have to be a proper wasm table because it is
-+    // only ever called from javascript
-+    var dyncallInvokeMap=new Map();
-+#endif
-diff --git a/emsdk/upstream/emscripten/tools/shared.py b/emsdk/upstream/emscripten/tools/shared.py
-index 74666ee..3d5657b 100644
---- a/emsdk/upstream/emscripten/tools/shared.py
-+++ b/emsdk/upstream/emscripten/tools/shared.py
-@@ -844,7 +844,7 @@ class JS(object):
-       else:
-         return 'Module["dynCall_%s"](%s)' % (sig, args)
-     else:
--      return 'wasmTable.get(%s)(%s)' % (args[0], ','.join(args[1:]))
-+        return 'dynCall("%s",%s,[%s])' %(sig,args[0],','.join(args[1:]))
- 
-   @staticmethod
-   def make_invoke(sig, named=True):
-diff --git a/emdsk/upstream/emscripten/src/library_dylink.js b/emsdk/upstream/emscripten/src/library_dylink.js
-index 876492b..750a18d 100644
---- a/emdsk/upstream/emscripten/src/library_dylink.js
-+++ b/emsdk/upstream/emscripten/src/library_dylink.js
-@@ -90,33 +93,84 @@ var LibraryDylink = {
-       var value = exports[symName];
- #if !WASM_BIGINT
-       if (symName.indexOf('orig$') == 0) {
--        symName = symName.split('$')[1];
-+        symName = symName.substring(5);
-         replace = true;
-       }
- #endif
--
--      if (!GOT[symName]) {
--        GOT[symName] = new WebAssembly.Global({value: 'i32', mutable: true});
-+      baseName=symName;
-+#if EMULATE_FUNCTION_POINTER_CASTS==1
-+      const FPCAST_PREFIX="byn$fpcast-emu$";
-+      const FPCAST_DYNCALL_PREFIX="$no-fpcast-emu$";
-+      var dyncallName;
-+      var is_fpcast=false;
-+      var is_nonfpcast=false;
-+      var newFn;
-+      if(typeof(value) === 'function')
-+      {
-+          if(symName.startsWith(FPCAST_PREFIX))
-+          {
-+              baseName=symName.substr(FPCAST_PREFIX.length);
-+              dyncallName=FPCAST_DYNCALL_PREFIX+baseName;
-+              is_fpcast=true;
-+          }else
-+          {
-+             if(FPCAST_PREFIX+symName in exports)
-+             {
-+                 baseName=FPCAST_DYNCALL_PREFIX+symName;
-+                 is_nonfpcast=true;
-+             }
-+          }
-       }
--      if (replace || GOT[symName].value == 0) {
-+#endif
-+      if (!GOT[baseName]) {
-+        GOT[baseName] = new WebAssembly.Global({value: 'i32', mutable: true});
-+      }
-+      if (replace || GOT[baseName].value == 0) {
-         if (typeof value === 'function') {
--          GOT[symName].value = addFunctionWasm(value);
-+          newFn=addFunctionWasm(value);
-+          GOT[baseName].value = newFn
- #if DYLINK_DEBUG
--          err("updateGOT FUNC: " + symName + ' : ' + GOT[symName].value);
-+          err("updateGOT FUNC: " + symName + ' : ' + GOT[baseName].value);
- #endif
-         } else if (typeof value === 'number') {
--          GOT[symName].value = value;
-+          GOT[baseName].value = value;
-         } else {
-           err("unhandled export type for `" + symName + "`: " + (typeof value));
-         }
- #if DYLINK_DEBUG
--        err("updateGOT: " + symName + ' : ' + GOT[symName].value);
-+        err("updateGOT: " + baseName + "("+ symName + ")" + ' : ' + GOT[symName].value);
- #endif
-       }
- #if DYLINK_DEBUG
--      else if (GOT[symName].value != value) {
--        err("updateGOT: EXISTING SYMBOL: " + symName + ' : ' + GOT[symName].value + " " + value);
-+      else if (GOT[baseName].value != value) {
-+        err("updateGOT: EXISTING SYMBOL: " + symName + ' : ' + GOT[baseName].value + " " + value);
-       }
-+#endif
-+#if EMULATE_FUNCTION_POINTER_CASTS==1
-+        // update map for dynamic calls so they can bypass fp casts
-+        if(!newFn)newFn= GOT[baseName].value;
-+        if(is_fpcast && newFn)
-+        {
-+            dyncallGOT=GOT[dyncallName]
-+            if(dyncallGOT){
-+                dcVal=dyncallGOT.value;
-+                if(dcVal)
-+                {
-+                    dyncallInvokeMap[newFn]=dcVal;
-+                }
-+            }
-+        }else if(is_nonfpcast && newFn)
-+        {
-+            fpcGOT=GOT[symName];
-+            if(fpcGOT)
-+            {
-+                fpVal=fpcGOT.value;
-+                if(fpVal)
-+                {
-+                    dyncallInvokeMap[fpVal]=newFn;
-+                }
-+            }
-+        }
- #endif
-     }
- #if DYLINK_DEBUG
-@@ -713,6 +769,8 @@ var LibraryDylink = {
-       nodelete: Boolean(flags & {{{ cDefine('RTLD_NODELETE') }}}),
-
-       fs: FS, // load libraries from provided filesystem
-+      allowUndefined: true, // allow undefined symbols - otherwise scipy won't
-+                            // import because modules have cross dependencies
-     }
-
-     try {
-@@ -754,6 +812,10 @@ var LibraryDylink = {
-     // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
-     symbol = UTF8ToString(symbol);
-     var result;
-+#if EMULATE_FUNCTION_POINTER_CASTS==1
-+      // look for fpcast-emu version as this is deffo going to be a function pointer that we return
-+      symbol="byn$fpcast-emu$"+symbol
-+#endif
-
-     if (handle == {{{ cDefine('RTLD_DEFAULT') }}}) {
-       result = resolveGlobalSymbol(symbol, true);
diff --git a/emsdk/patches/fix_emulate_pointers_dlsym.patch b/emsdk/patches/fix_emulate_pointers_dlsym.patch
deleted file mode 100644
index cc6a3801640..00000000000
--- a/emsdk/patches/fix_emulate_pointers_dlsym.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-diff --git a/emsdk/binary/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp
-index 9d232c9..60d3990 100644
---- a/emsdk/binaryen/src/passes/FuncCastEmulation.cpp
-+++ b/emsdk/binaryen/src/passes/FuncCastEmulation.cpp
-@@ -170,23 +170,86 @@ struct FuncCastEmulation : public Pass {
-       std::stoul(runner->options.getArgumentOrDefault("max-func-params", "16"));
-     // we just need the one ABI function type for all indirect calls
-     Signature ABIType(Type(std::vector<Type>(numParams, Type::i64)), Type::i64);
--    // Add a thunk for each function in the table, and do the call through it.
-+
-+    // make sure everything in exports has a thunk
-+    // so dlsym works
-     std::unordered_map<Name, Name> funcThunks;
-+    std::unordered_map<Name, Name> exportThunks;
-+    for(auto& function: module->exports)
-+    {
-+        auto& exportName=function->name;
-+        auto& exportValue=function->value;
-+        // don't create FPCAST emulation for javascript legalizer stubs
-+        // (used when javascript doesn't have 64 bit support, so 
-+        // can't use fpcast emulation calls which need 64 bit support)
-+        if(module->getFunctionOrNull(exportValue) && strncmp(exportValue.str,"legalstub$",10)!=0 )
-+        {
-+          Name exportThunkName = std::string("byn$fpcast-emu$") + exportName.str;
-+          auto iter = funcThunks.find(exportValue);          
-+          if (iter == funcThunks.end()) 
-+          {
-+            // an export without a thunk yet - make it and export it
-+            auto thunk = makeThunk(exportValue, module, numParams);
-+            funcThunks[exportValue] = thunk;
-+            exportThunks[exportThunkName]=thunk;
-+          }else
-+          {
-+            // just export existing thunk
-+            exportThunks[exportThunkName]=iter->second;
-+          }
-+       }
-+     }
-+    int exportCount=0;
-+    // Add a thunk for each function in the table, and do the call through it.
-     for (auto& table : module->tables) {
-       for (auto& segment : table->segments) {
-         for (auto& name : segment.data) {
--          auto iter = funcThunks.find(name);
--          if (iter == funcThunks.end()) {
--            auto thunk = makeThunk(name, module, numParams);
--            funcThunks[name] = thunk;
--            name = thunk;
--          } else {
--            name = iter->second;
-+          // don't create FPCAST emulation for javascript legalizer stubs
-+          // (used when javascript doesn't have 64 bit support, so
-+          // can't use fpcast emulation calls which need 64 bit support)
-+          if(strncmp(name.str,"legalstub$",10)!=0) {
-+            auto iter = funcThunks.find(name);
-+            if (iter == funcThunks.end()) {
-+              // we've already made thunks for exported funcionts so
-+              // this is a static function - make the thunk and make an anon export 
-+              // to it so that it can be called by pyodide
-+              Name orig_name(name);
-+              auto thunk = makeThunk(name, module, numParams);
-+              funcThunks[name] = thunk;
-+              exportCount+=1;
-+              char buffer[256];
-+              snprintf(buffer,256,"byn$fpcast-emu$__static_%d",exportCount);
-+              // first make the fpcast version of the function
-+              auto* export_ = new Export;
-+              export_->name = buffer;
-+              export_->value = thunk;
-+              export_->kind = ExternalKind::Function;
-+              module->addExport(export_);
-+              // now make the non-fpcast version
-+              snprintf(buffer,256,"__static_%d",exportCount);
-+              auto* export2_ = new Export;
-+              export2_->name = buffer;
-+              export2_->value = orig_name;
-+              export2_->kind = ExternalKind::Function;
-+              module->addExport(export2_);
-+              name = thunk;
-+            } else {
-+              name = iter->second;
-+            }
-           }
-         }
-       }
-     }
-
-+    // make exports for all export thunks    
-+    for(auto& thunk: exportThunks) {
-+        auto* export_ = new Export;
-+        export_->name = thunk.first;
-+        export_->value = thunk.second;
-+        export_->kind = ExternalKind::Function;
-+        module->addExport(export_);
-+    }
-+
-     // update call_indirects
-     ParallelFuncCastEmulation(ABIType, numParams).run(runner, module);
-   }
diff --git a/emsdk/tests/__init__.py b/emsdk/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/emsdk/tests/common.py b/emsdk/tests/common.py
deleted file mode 100644
index fed95d400c8..00000000000
--- a/emsdk/tests/common.py
+++ /dev/null
@@ -1,33 +0,0 @@
-MAIN_C = r"""
-#include <stdio.h>
-#include <dlfcn.h>
-#include <setjmp.h>
-
-void never_called()
-{
-    jmp_buf buf;
-    int i=setjmp(buf);
-    longjmp(buf,1);
-}
-
-
-int main() {
-  puts("hello from main");
-  void *handle = dlopen("library.wasm", RTLD_NOW);
-  if (!handle) {
-    puts("cannot load side module");
-    puts(dlerror());
-    return 1;
-  }
-  typedef void (*type_v)();
-  type_v side_func = (type_v) dlsym(handle, "foo");
-  if (!side_func) {
-    puts("cannot load side function");
-    puts(dlerror());
-    return 1;
-  } else {
-    side_func();
-  }
-  return 0;
-}
-"""
diff --git a/emsdk/tests/test_dyncall.py b/emsdk/tests/test_dyncall.py
deleted file mode 100644
index 7615e14e4e3..00000000000
--- a/emsdk/tests/test_dyncall.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import subprocess
-from . import common
-
-
-def test_dyncall(tmpdir):
-    with tmpdir.as_cwd():
-        with open("library.c", "w") as f:
-            f.write(
-                """\
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include <assert.h>
-
-// This can be any function that has a signature not found in main.
-__attribute__ ((noinline)) int indirect_function(int a, float b, int c, double d) {
-  return a;
-}
-
-typedef int (*type_iifid) (int, float, int, double);
-
-void foo() {
-  // Hack to force inclusion of malloc
-  volatile int x = (int) malloc(1);
-  free((void *) x);
-
-  type_iifid fp = &indirect_function;
-
-  jmp_buf buf;
-  int i = setjmp(buf);
-
-  printf("%d\\n", i);
-  assert(fp(i, 0, 0, 0) == i);
-
-  if (i == 0) longjmp(buf, 1);
-
-}
-"""
-            )
-        with open("main.c", "w") as f:
-            f.write(common.MAIN_C)
-
-        subprocess.run(
-            [
-                "emcc",
-                "-g4",
-                "-s",
-                "SIDE_MODULE=1",
-                "library.c",
-                "-o",
-                "library.wasm",
-                "-s",
-                "EMULATE_FUNCTION_POINTER_CASTS=1",
-                "-s",
-                "EXPORT_ALL=1",
-            ],
-            check=True,
-        )
-        subprocess.run(
-            [
-                "emcc",
-                "-g4",
-                "-s",
-                "MAIN_MODULE=1",
-                "main.c",
-                "--embed-file",
-                "library.wasm",
-                "-s",
-                "EMULATE_FUNCTION_POINTER_CASTS=1",
-            ],
-            check=True,
-        )
-        out = subprocess.run(["node", "a.out.js"], capture_output=True, check=True)
-        assert out.stdout == b"hello from main\n0\n1\n"
diff --git a/emsdk/tests/test_emulate.py b/emsdk/tests/test_emulate.py
deleted file mode 100644
index f53be7ae1bf..00000000000
--- a/emsdk/tests/test_emulate.py
+++ /dev/null
@@ -1,55 +0,0 @@
-import subprocess
-from . import common
-
-
-def test_emulate_function(tmpdir):
-    with tmpdir.as_cwd():
-        with open("library.c", "w") as f:
-            f.write(
-                """\
-#include <stdio.h>
-
-// emulate function pointer casts - this has the
-// wrong arguments and return type
-int foo(int extra_args) {
-  puts("hello from library");
-  return 0;
-}"""
-            )
-        with open("main.c", "w") as f:
-            f.write(common.MAIN_C)
-
-        subprocess.run(
-            [
-                "emcc",
-                "-g",
-                "-s",
-                "SIDE_MODULE=1",
-                "library.c",
-                "-o",
-                "library.wasm",
-                "-s",
-                "EMULATE_FUNCTION_POINTER_CASTS=1",
-                "-s",
-                "EXPORT_ALL=1",
-            ],
-            check=True,
-        )
-        subprocess.run(
-            [
-                "emcc",
-                "-g",
-                "-s",
-                "MAIN_MODULE=1",
-                "main.c",
-                "--embed-file",
-                "library.wasm",
-                "-s",
-                "EMULATE_FUNCTION_POINTER_CASTS=1",
-                "-s",
-                "EXPORT_ALL=1",
-            ],
-            check=True,
-        )
-        out = subprocess.run(["node", "a.out.js"], capture_output=True, check=True)
-        assert out.stdout == b"hello from main\nhello from library\n"
diff --git a/packages/cffi_example/test_cffi_example.py b/packages/cffi_example/test_cffi_example.py
index 10eee64ec5f..958a7a5d42c 100644
--- a/packages/cffi_example/test_cffi_example.py
+++ b/packages/cffi_example/test_cffi_example.py
@@ -13,6 +13,8 @@
 )
 def test_fnmatch(selenium_module_scope, pattern, name, flags, expected):
     selenium = selenium_module_scope
+    if selenium.browser == "chrome":
+        pytest.xfail("Doesn't work in chrome v90")
     selenium.load_package("cffi_example")
     result = selenium.run(
         f"""
@@ -23,7 +25,11 @@ def test_fnmatch(selenium_module_scope, pattern, name, flags, expected):
     assert result == expected
 
 
-@run_in_pyodide(packages=["cffi_example"], module_scope=True)
+@run_in_pyodide(
+    packages=["cffi_example"],
+    module_scope=True,
+    xfail_browsers={"chrome": "Doesn't work in chrome v90"},
+)
 def test_person():
     from cffi_example.person import Person
 
diff --git a/packages/numpy/meta.yaml b/packages/numpy/meta.yaml
index 1df661104ca..eeebdb0f0a4 100644
--- a/packages/numpy/meta.yaml
+++ b/packages/numpy/meta.yaml
@@ -18,7 +18,6 @@ source:
     - patches/fix-install-with-skip-build.patch
     - patches/make-int-return-values.patch
     - patches/fix-ieee754.patch
-    - patches/fix-getters.patch
     - patches/disable-optimization.patch
     - patches/not-build-lapack-lite-as-64-bit.patch
     - patches/fix-invalid-asm-instruction.patch
diff --git a/packages/numpy/patches/fix-getters.patch b/packages/numpy/patches/fix-getters.patch
deleted file mode 100644
index 0dc87fe3c7c..00000000000
--- a/packages/numpy/patches/fix-getters.patch
+++ /dev/null
@@ -1,918 +0,0 @@
-diff --git a/numpy/core/src/multiarray/datetime_busdaycal.c b/numpy/core/src/multiarray/datetime_busdaycal.c
-index d48141d4c..6d02cf62c 100644
---- a/numpy/core/src/multiarray/datetime_busdaycal.c
-+++ b/numpy/core/src/multiarray/datetime_busdaycal.c
-@@ -434,7 +434,7 @@ busdaycalendar_dealloc(NpyBusDayCalendar *self)
- }
- 
- static PyObject *
--busdaycalendar_weekmask_get(NpyBusDayCalendar *self)
-+busdaycalendar_weekmask_get(NpyBusDayCalendar *self,void* ignored)
- {
-     PyArrayObject *ret;
-     npy_intp size = 7;
-@@ -452,7 +452,7 @@ busdaycalendar_weekmask_get(NpyBusDayCalendar *self)
- }
- 
- static PyObject *
--busdaycalendar_holidays_get(NpyBusDayCalendar *self)
-+busdaycalendar_holidays_get(NpyBusDayCalendar *self,void* ignored)
- {
-     PyArrayObject *ret;
-     PyArray_Descr *date_dtype;
-diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
-index b8b477e5d..7f8c33251 100644
---- a/numpy/core/src/multiarray/descriptor.c
-+++ b/numpy/core/src/multiarray/descriptor.c
-@@ -1895,7 +1895,7 @@ static PyMemberDef arraydescr_members[] = {
- };
- 
- static PyObject *
--arraydescr_subdescr_get(PyArray_Descr *self)
-+arraydescr_subdescr_get(PyArray_Descr *self,void *ignored)
- {
-     if (!PyDataType_HASSUBARRAY(self)) {
-         Py_RETURN_NONE;
-@@ -1905,7 +1905,7 @@ arraydescr_subdescr_get(PyArray_Descr *self)
- }
- 
- NPY_NO_EXPORT PyObject *
--arraydescr_protocol_typestr_get(PyArray_Descr *self)
-+arraydescr_protocol_typestr_get(PyArray_Descr *self,void*ignored)
- {
-     char basic_ = self->kind;
-     char endian = self->byteorder;
-@@ -1951,7 +1951,7 @@ arraydescr_protocol_typestr_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_name_get(PyArray_Descr *self)
-+arraydescr_name_get(PyArray_Descr *self,void* ignored)
- {
-     /* let python handle this */
-     PyObject *_numpy_dtype;
-@@ -1966,7 +1966,7 @@ arraydescr_name_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_base_get(PyArray_Descr *self)
-+arraydescr_base_get(PyArray_Descr *self,void* ignored)
- {
-     if (!PyDataType_HASSUBARRAY(self)) {
-         Py_INCREF(self);
-@@ -1977,7 +1977,7 @@ arraydescr_base_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_shape_get(PyArray_Descr *self)
-+arraydescr_shape_get(PyArray_Descr *self,void* ignored)
- {
-     if (!PyDataType_HASSUBARRAY(self)) {
-         return PyTuple_New(0);
-@@ -1988,7 +1988,7 @@ arraydescr_shape_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_ndim_get(PyArray_Descr *self)
-+arraydescr_ndim_get(PyArray_Descr *self,void* ignored)
- {
-     Py_ssize_t ndim;
- 
-@@ -2006,7 +2006,7 @@ arraydescr_ndim_get(PyArray_Descr *self)
- 
- 
- NPY_NO_EXPORT PyObject *
--arraydescr_protocol_descr_get(PyArray_Descr *self)
-+arraydescr_protocol_descr_get(PyArray_Descr *self,void* ignored)
- {
-     PyObject *dobj, *res;
-     PyObject *_numpy_internal;
-@@ -2018,7 +2018,7 @@ arraydescr_protocol_descr_get(PyArray_Descr *self)
-             return NULL;
-         }
-         PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
--        PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self));
-+        PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self, NULL));
-         res = PyList_New(1);
-         if (res == NULL) {
-             Py_DECREF(dobj);
-@@ -2043,7 +2043,7 @@ arraydescr_protocol_descr_get(PyArray_Descr *self)
-  * return 0 if neither (i.e. it's a copy of one)
-  */
- static PyObject *
--arraydescr_isbuiltin_get(PyArray_Descr *self)
-+arraydescr_isbuiltin_get(PyArray_Descr *self,void *ignored)
- {
-     long val;
-     val = 0;
-@@ -2090,7 +2090,7 @@ _arraydescr_isnative(PyArray_Descr *self)
-  * fields are defined
-  */
- static PyObject *
--arraydescr_isnative_get(PyArray_Descr *self)
-+arraydescr_isnative_get(PyArray_Descr *self,void* ignored)
- {
-     PyObject *ret;
-     int retval;
-@@ -2104,7 +2104,7 @@ arraydescr_isnative_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_isalignedstruct_get(PyArray_Descr *self)
-+arraydescr_isalignedstruct_get(PyArray_Descr *self,void* ignored)
- {
-     PyObject *ret;
-     ret = (self->flags&NPY_ALIGNED_STRUCT) ? Py_True : Py_False;
-@@ -2113,7 +2113,7 @@ arraydescr_isalignedstruct_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_fields_get(PyArray_Descr *self)
-+arraydescr_fields_get(PyArray_Descr *self,void* ignored)
- {
-     if (!PyDataType_HASFIELDS(self)) {
-         Py_RETURN_NONE;
-@@ -2122,7 +2122,7 @@ arraydescr_fields_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_metadata_get(PyArray_Descr *self)
-+arraydescr_metadata_get(PyArray_Descr *self,void* ignored)
- {
-     if (self->metadata == NULL) {
-         Py_RETURN_NONE;
-@@ -2131,7 +2131,7 @@ arraydescr_metadata_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_hasobject_get(PyArray_Descr *self)
-+arraydescr_hasobject_get(PyArray_Descr *self,void* ignored)
- {
-     if (PyDataType_FLAGCHK(self, NPY_ITEM_HASOBJECT)) {
-         Py_RETURN_TRUE;
-@@ -2142,7 +2142,7 @@ arraydescr_hasobject_get(PyArray_Descr *self)
- }
- 
- static PyObject *
--arraydescr_names_get(PyArray_Descr *self)
-+arraydescr_names_get(PyArray_Descr *self,void* ignored)
- {
-     if (!PyDataType_HASFIELDS(self)) {
-         Py_RETURN_NONE;
-@@ -2152,7 +2152,7 @@ arraydescr_names_get(PyArray_Descr *self)
- }
- 
- static int
--arraydescr_names_set(PyArray_Descr *self, PyObject *val)
-+arraydescr_names_set(PyArray_Descr *self, PyObject *val,void* ignored)
- {
-     int N = 0;
-     int i;
-@@ -2536,7 +2536,7 @@ arraydescr_reduce(PyArray_Descr *self, PyObject *NPY_UNUSED(args))
-     }
- 
-     PyTuple_SET_ITEM(state, 1, PyUnicode_FromFormat("%c", endian));
--    PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self));
-+    PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self, NULL));
-     if (PyDataType_HASFIELDS(self)) {
-         Py_INCREF(self->names);
-         Py_INCREF(self->fields);
-diff --git a/numpy/core/src/multiarray/descriptor.h b/numpy/core/src/multiarray/descriptor.h
-index fc9e0895b..ac5d1db67 100644
---- a/numpy/core/src/multiarray/descriptor.h
-+++ b/numpy/core/src/multiarray/descriptor.h
-@@ -1,8 +1,8 @@
- #ifndef _NPY_ARRAYDESCR_H_
- #define _NPY_ARRAYDESCR_H_
- 
--NPY_NO_EXPORT PyObject *arraydescr_protocol_typestr_get(PyArray_Descr *);
--NPY_NO_EXPORT PyObject *arraydescr_protocol_descr_get(PyArray_Descr *self);
-+NPY_NO_EXPORT PyObject *arraydescr_protocol_typestr_get(PyArray_Descr *,void*);
-+NPY_NO_EXPORT PyObject *arraydescr_protocol_descr_get(PyArray_Descr *self,void*);
- 
- NPY_NO_EXPORT PyObject *
- array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args);
-diff --git a/numpy/core/src/multiarray/flagsobject.c b/numpy/core/src/multiarray/flagsobject.c
-index 9b7d8deae..15add48f8 100644
---- a/numpy/core/src/multiarray/flagsobject.c
-+++ b/numpy/core/src/multiarray/flagsobject.c
-@@ -200,7 +200,7 @@ arrayflags_dealloc(PyArrayFlagsObject *self)
- 
- #define _define_get(UPPER, lower) \
-     static PyObject * \
--    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self) \
-+    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self,void* ignored) \
-     { \
-         return PyBool_FromLong((self->flags & (UPPER)) == (UPPER)); \
-     }
-@@ -211,7 +211,7 @@ static char *msg = "future versions will not create a writeable "
- 
- #define _define_get_warn(UPPER, lower) \
-     static PyObject * \
--    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self) \
-+    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self,void* ignored) \
-     { \
-         if (self->flags & NPY_ARRAY_WARN_ON_WRITE) { \
-             if (PyErr_Warn(PyExc_FutureWarning, msg) < 0) {\
-@@ -236,7 +236,7 @@ _define_get_warn(NPY_ARRAY_ALIGNED|
-             NPY_ARRAY_C_CONTIGUOUS, carray)
- 
- static PyObject *
--arrayflags_updateifcopy_get(PyArrayFlagsObject *self)
-+arrayflags_updateifcopy_get(PyArrayFlagsObject *self,void* ignored)
- {
-     PyObject *item;
-     /* 2017-Nov-10 1.14 */
-@@ -255,7 +255,7 @@ arrayflags_updateifcopy_get(PyArrayFlagsObject *self)
- 
- 
- static PyObject *
--arrayflags_forc_get(PyArrayFlagsObject *self)
-+arrayflags_forc_get(PyArrayFlagsObject *self,void* ignored)
- {
-     PyObject *item;
- 
-@@ -271,7 +271,7 @@ arrayflags_forc_get(PyArrayFlagsObject *self)
- }
- 
- static PyObject *
--arrayflags_fnc_get(PyArrayFlagsObject *self)
-+arrayflags_fnc_get(PyArrayFlagsObject *self,void* ignored)
- {
-     PyObject *item;
- 
-@@ -287,7 +287,7 @@ arrayflags_fnc_get(PyArrayFlagsObject *self)
- }
- 
- static PyObject *
--arrayflags_farray_get(PyArrayFlagsObject *self)
-+arrayflags_farray_get(PyArrayFlagsObject *self,void* ignored)
- {
-     PyObject *item;
- 
-@@ -312,7 +312,7 @@ arrayflags_num_get(PyArrayFlagsObject *self)
- 
- /* relies on setflags order being write, align, uic */
- static int
--arrayflags_updateifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
-+arrayflags_updateifcopy_set(PyArrayFlagsObject *self, PyObject *obj,void* ignored)
- {
-     PyObject *res;
- 
-@@ -341,7 +341,7 @@ arrayflags_updateifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
- 
- /* relies on setflags order being write, align, uic */
- static int
--arrayflags_writebackifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
-+arrayflags_writebackifcopy_set(PyArrayFlagsObject *self, PyObject *obj,void* ignored)
- {
-     PyObject *res;
- 
-@@ -365,7 +365,7 @@ arrayflags_writebackifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
- }
- 
- static int
--arrayflags_aligned_set(PyArrayFlagsObject *self, PyObject *obj)
-+arrayflags_aligned_set(PyArrayFlagsObject *self, PyObject *obj,void* ignored)
- {
-     PyObject *res;
- 
-@@ -390,7 +390,7 @@ arrayflags_aligned_set(PyArrayFlagsObject *self, PyObject *obj)
- }
- 
- static int
--arrayflags_writeable_set(PyArrayFlagsObject *self, PyObject *obj)
-+arrayflags_writeable_set(PyArrayFlagsObject *self, PyObject *obj,void* ignored)
- {
-     PyObject *res;
- 
-@@ -415,7 +415,7 @@ arrayflags_writeable_set(PyArrayFlagsObject *self, PyObject *obj)
- }
- 
- static int
--arrayflags_warn_on_write_set(PyArrayFlagsObject *self, PyObject *obj)
-+arrayflags_warn_on_write_set(PyArrayFlagsObject *self, PyObject *obj,void* ignored)
- {
-     /*
-      * This code should go away in a future release, so do not mangle the
-@@ -554,89 +554,89 @@ arrayflags_getitem(PyArrayFlagsObject *self, PyObject *ind)
-     case 1:
-         switch(key[0]) {
-         case 'C':
--            return arrayflags_contiguous_get(self);
-+            return arrayflags_contiguous_get(self,NULL);
-         case 'F':
--            return arrayflags_fortran_get(self);
-+            return arrayflags_fortran_get(self,NULL);
-         case 'W':
--            return arrayflags_writeable_get(self);
-+            return arrayflags_writeable_get(self,NULL);
-         case 'B':
--            return arrayflags_behaved_get(self);
-+            return arrayflags_behaved_get(self,NULL);
-         case 'O':
--            return arrayflags_owndata_get(self);
-+            return arrayflags_owndata_get(self,NULL);
-         case 'A':
--            return arrayflags_aligned_get(self);
-+            return arrayflags_aligned_get(self,NULL);
-         case 'X':
--            return arrayflags_writebackifcopy_get(self);
-+            return arrayflags_writebackifcopy_get(self,NULL);
-         case 'U':
--            return arrayflags_updateifcopy_get(self);
-+            return arrayflags_updateifcopy_get(self,NULL);
-         default:
-             goto fail;
-         }
-         break;
-     case 2:
-         if (strncmp(key, "CA", n) == 0) {
--            return arrayflags_carray_get(self);
-+            return arrayflags_carray_get(self,NULL);
-         }
-         if (strncmp(key, "FA", n) == 0) {
--            return arrayflags_farray_get(self);
-+            return arrayflags_farray_get(self,NULL);
-         }
-         break;
-     case 3:
-         if (strncmp(key, "FNC", n) == 0) {
--            return arrayflags_fnc_get(self);
-+            return arrayflags_fnc_get(self,NULL);
-         }
-         break;
-     case 4:
-         if (strncmp(key, "FORC", n) == 0) {
--            return arrayflags_forc_get(self);
-+            return arrayflags_forc_get(self,NULL);
-         }
-         break;
-     case 6:
-         if (strncmp(key, "CARRAY", n) == 0) {
--            return arrayflags_carray_get(self);
-+            return arrayflags_carray_get(self,NULL);
-         }
-         if (strncmp(key, "FARRAY", n) == 0) {
--            return arrayflags_farray_get(self);
-+            return arrayflags_farray_get(self,NULL);
-         }
-         break;
-     case 7:
-         if (strncmp(key,"FORTRAN",n) == 0) {
--            return arrayflags_fortran_get(self);
-+            return arrayflags_fortran_get(self,NULL);
-         }
-         if (strncmp(key,"BEHAVED",n) == 0) {
--            return arrayflags_behaved_get(self);
-+            return arrayflags_behaved_get(self,NULL);
-         }
-         if (strncmp(key,"OWNDATA",n) == 0) {
--            return arrayflags_owndata_get(self);
-+            return arrayflags_owndata_get(self,NULL);
-         }
-         if (strncmp(key,"ALIGNED",n) == 0) {
--            return arrayflags_aligned_get(self);
-+            return arrayflags_aligned_get(self,NULL);
-         }
-         break;
-     case 9:
-         if (strncmp(key,"WRITEABLE",n) == 0) {
--            return arrayflags_writeable_get(self);
-+            return arrayflags_writeable_get(self,NULL);
-         }
-         break;
-     case 10:
-         if (strncmp(key,"CONTIGUOUS",n) == 0) {
--            return arrayflags_contiguous_get(self);
-+            return arrayflags_contiguous_get(self,NULL);
-         }
-         break;
-     case 12:
-         if (strncmp(key, "UPDATEIFCOPY", n) == 0) {
--            return arrayflags_updateifcopy_get(self);
-+            return arrayflags_updateifcopy_get(self,NULL);
-         }
-         if (strncmp(key, "C_CONTIGUOUS", n) == 0) {
--            return arrayflags_contiguous_get(self);
-+            return arrayflags_contiguous_get(self,NULL);
-         }
-         if (strncmp(key, "F_CONTIGUOUS", n) == 0) {
--            return arrayflags_fortran_get(self);
-+            return arrayflags_fortran_get(self,NULL);
-         }
-         break;
-     case 15:
-         if (strncmp(key, "WRITEBACKIFCOPY", n) == 0) {
--            return arrayflags_writebackifcopy_get(self);
-+            return arrayflags_writebackifcopy_get(self,NULL);
-         }
-         break;
-     }
-@@ -671,19 +671,19 @@ arrayflags_setitem(PyArrayFlagsObject *self, PyObject *ind, PyObject *item)
-     }
-     if (((n==9) && (strncmp(key, "WRITEABLE", n) == 0)) ||
-         ((n==1) && (strncmp(key, "W", n) == 0))) {
--        return arrayflags_writeable_set(self, item);
-+        return arrayflags_writeable_set(self, item,NULL);
-     }
-     else if (((n==7) && (strncmp(key, "ALIGNED", n) == 0)) ||
-              ((n==1) && (strncmp(key, "A", n) == 0))) {
--        return arrayflags_aligned_set(self, item);
-+        return arrayflags_aligned_set(self, item,NULL);
-     }
-     else if (((n==12) && (strncmp(key, "UPDATEIFCOPY", n) == 0)) ||
-              ((n==1) && (strncmp(key, "U", n) == 0))) {
--        return arrayflags_updateifcopy_set(self, item);
-+        return arrayflags_updateifcopy_set(self, item,NULL);
-     }
-     else if (((n==15) && (strncmp(key, "WRITEBACKIFCOPY", n) == 0)) ||
-              ((n==1) && (strncmp(key, "X", n) == 0))) {
--        return arrayflags_writebackifcopy_set(self, item);
-+        return arrayflags_writebackifcopy_set(self, item,NULL);
-     }
- 
-  fail:
-diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
-index bccbb7b0c..f07151ee0 100644
---- a/numpy/core/src/multiarray/getset.c
-+++ b/numpy/core/src/multiarray/getset.c
-@@ -190,7 +190,7 @@ array_priority_get(PyArrayObject *NPY_UNUSED(self))
- static PyObject *
- array_typestr_get(PyArrayObject *self)
- {
--    return arraydescr_protocol_typestr_get(PyArray_DESCR(self));
-+    return arraydescr_protocol_typestr_get(PyArray_DESCR(self), NULL);
- }
- 
- static PyObject *
-@@ -206,7 +206,7 @@ array_protocol_descr_get(PyArrayObject *self)
-     PyObject *res;
-     PyObject *dobj;
- 
--    res = arraydescr_protocol_descr_get(PyArray_DESCR(self));
-+    res = arraydescr_protocol_descr_get(PyArray_DESCR(self), NULL);
-     if (res) {
-         return res;
-     }
-@@ -229,7 +229,7 @@ array_protocol_descr_get(PyArrayObject *self)
- }
- 
- static PyObject *
--array_protocol_strides_get(PyArrayObject *self)
-+array_protocol_strides_get(PyArrayObject *self,void* ignored)
- {
-     if (PyArray_ISCONTIGUOUS(self)) {
-         Py_RETURN_NONE;
-@@ -240,7 +240,7 @@ array_protocol_strides_get(PyArrayObject *self)
- 
- 
- static PyObject *
--array_dataptr_get(PyArrayObject *self)
-+array_dataptr_get(PyArrayObject *self,void* ignored)
- {
-     return Py_BuildValue("NO",
-                          PyLong_FromVoidPtr(PyArray_DATA(self)),
-@@ -250,7 +250,7 @@ array_dataptr_get(PyArrayObject *self)
- }
- 
- static PyObject *
--array_ctypes_get(PyArrayObject *self)
-+array_ctypes_get(PyArrayObject *self,void* ignored)
- {
-     PyObject *_numpy_internal;
-     PyObject *ret;
-@@ -265,7 +265,7 @@ array_ctypes_get(PyArrayObject *self)
- }
- 
- static PyObject *
--array_interface_get(PyArrayObject *self)
-+array_interface_get(PyArrayObject *self,void* ignored)
- {
-     PyObject *dict;
-     PyObject *obj;
-@@ -278,7 +278,7 @@ array_interface_get(PyArrayObject *self)
-     int ret;
- 
-     /* dataptr */
--    obj = array_dataptr_get(self);
-+    obj = array_dataptr_get(self, NULL);
-     ret = PyDict_SetItemString(dict, "data", obj);
-     Py_DECREF(obj);
-     if (ret < 0) {
-@@ -286,7 +286,7 @@ array_interface_get(PyArrayObject *self)
-         return NULL;
-     }
- 
--    obj = array_protocol_strides_get(self);
-+    obj = array_protocol_strides_get(self, NULL);
-     ret = PyDict_SetItemString(dict, "strides", obj);
-     Py_DECREF(obj);
-     if (ret < 0) {
-@@ -302,7 +302,7 @@ array_interface_get(PyArrayObject *self)
-         return NULL;
-     }
- 
--    obj = arraydescr_protocol_typestr_get(PyArray_DESCR(self));
-+    obj = arraydescr_protocol_typestr_get(PyArray_DESCR(self), NULL);
-     ret = PyDict_SetItemString(dict, "typestr", obj);
-     Py_DECREF(obj);
-     if (ret < 0) {
-@@ -336,7 +336,7 @@ array_data_get(PyArrayObject *self)
- }
- 
- static int
--array_data_set(PyArrayObject *self, PyObject *op)
-+array_data_set(PyArrayObject *self, PyObject *op,void* ignored)
- {
-     void *buf;
-     Py_ssize_t buf_len;
-@@ -438,7 +438,7 @@ array_nbytes_get(PyArrayObject *self)
-  * will be adjusted in that case as well.
-  */
- static int
--array_descr_set(PyArrayObject *self, PyObject *arg)
-+array_descr_set(PyArrayObject *self, PyObject *arg,void* ignored)
- {
-     PyArray_Descr *newtype = NULL;
- 
-@@ -641,7 +641,7 @@ array_struct_get(PyArrayObject *self)
-     }
-     inter->data = PyArray_DATA(self);
-     if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
--        inter->descr = arraydescr_protocol_descr_get(PyArray_DESCR(self));
-+        inter->descr = arraydescr_protocol_descr_get(PyArray_DESCR(self),NULL);
-         if (inter->descr == NULL) {
-             PyErr_Clear();
-         }
-@@ -664,7 +664,7 @@ array_struct_get(PyArrayObject *self)
- }
- 
- static PyObject *
--array_base_get(PyArrayObject *self)
-+array_base_get(PyArrayObject *self,void* ignored)
- {
-     if (PyArray_BASE(self) == NULL) {
-         Py_RETURN_NONE;
-@@ -734,7 +734,7 @@ _get_part(PyArrayObject *self, int imag)
-  */
- 
- static PyObject *
--array_real_get(PyArrayObject *self)
-+array_real_get(PyArrayObject *self,void* ignored)
- {
-     PyArrayObject *ret;
- 
-@@ -750,7 +750,7 @@ array_real_get(PyArrayObject *self)
- 
- 
- static int
--array_real_set(PyArrayObject *self, PyObject *val)
-+array_real_set(PyArrayObject *self, PyObject *val,void* ignored)
- {
-     PyArrayObject *ret;
-     PyArrayObject *new;
-@@ -788,7 +788,7 @@ array_real_set(PyArrayObject *self, PyObject *val)
- */
- 
- static PyObject *
--array_imag_get(PyArrayObject *self)
-+array_imag_get(PyArrayObject *self,void* ignored)
- {
-     PyArrayObject *ret;
- 
-@@ -816,7 +816,7 @@ array_imag_get(PyArrayObject *self)
- }
- 
- static int
--array_imag_set(PyArrayObject *self, PyObject *val)
-+array_imag_set(PyArrayObject *self, PyObject *val,void* ignored)
- {
-     if (val == NULL) {
-         PyErr_SetString(PyExc_AttributeError,
-@@ -850,13 +850,13 @@ array_imag_set(PyArrayObject *self, PyObject *val)
- }
- 
- static PyObject *
--array_flat_get(PyArrayObject *self)
-+array_flat_get(PyArrayObject *self,void* ignored)
- {
-     return PyArray_IterNew((PyObject *)self);
- }
- 
- static int
--array_flat_set(PyArrayObject *self, PyObject *val)
-+array_flat_set(PyArrayObject *self, PyObject *val,void* ignored)
- {
-     PyArrayObject *arr = NULL;
-     int retval = -1;
-@@ -928,7 +928,7 @@ array_flat_set(PyArrayObject *self, PyObject *val)
- }
- 
- static PyObject *
--array_transpose_get(PyArrayObject *self)
-+array_transpose_get(PyArrayObject *self,void* ignored)
- {
-     return PyArray_Transpose(self, NULL);
- }
-@@ -937,7 +937,7 @@ array_transpose_get(PyArrayObject *self)
-    --- default sub-class behavior
- */
- static PyObject *
--array_finalize_get(PyArrayObject *NPY_UNUSED(self))
-+array_finalize_get(PyArrayObject *NPY_UNUSED(self),void* ignored)
- {
-     Py_RETURN_NONE;
- }
-diff --git a/numpy/core/src/multiarray/iterators.c b/numpy/core/src/multiarray/iterators.c
-index 576ea89b3..0e5befcc8 100644
---- a/numpy/core/src/multiarray/iterators.c
-+++ b/numpy/core/src/multiarray/iterators.c
-@@ -1425,13 +1425,13 @@ arraymultiter_index_get(PyArrayMultiIterObject *self)
- }
- 
- static PyObject *
--arraymultiter_shape_get(PyArrayMultiIterObject *self)
-+arraymultiter_shape_get(PyArrayMultiIterObject *self,void* ignored)
- {
-     return PyArray_IntTupleFromIntp(self->nd, self->dimensions);
- }
- 
- static PyObject *
--arraymultiter_iters_get(PyArrayMultiIterObject *self)
-+arraymultiter_iters_get(PyArrayMultiIterObject *self,void* ignored)
- {
-     PyObject *res;
-     int i, n;
-diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c
-index 73df962e4..c1ae0039c 100644
---- a/numpy/core/src/multiarray/nditer_pywrap.c
-+++ b/numpy/core/src/multiarray/nditer_pywrap.c
-@@ -1384,7 +1384,7 @@ npyiter_debug_print(NewNpyArrayIterObject *self)
- NPY_NO_EXPORT PyObject *
- npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i);
- 
--static PyObject *npyiter_value_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_value_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     PyObject *ret;
- 
-@@ -1420,7 +1420,7 @@ static PyObject *npyiter_value_get(NewNpyArrayIterObject *self)
-     return ret;
- }
- 
--static PyObject *npyiter_operands_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_operands_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     PyObject *ret;
- 
-@@ -1449,7 +1449,7 @@ static PyObject *npyiter_operands_get(NewNpyArrayIterObject *self)
-     return ret;
- }
- 
--static PyObject *npyiter_itviews_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_itviews_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     PyObject *ret;
- 
-@@ -1508,7 +1508,7 @@ npyiter_next(NewNpyArrayIterObject *self)
-     }
-     self->started = 1;
- 
--    return npyiter_value_get(self);
-+    return npyiter_value_get(self, NULL);
- };
- 
- static PyObject *npyiter_shape_get(NewNpyArrayIterObject *self)
-@@ -1565,7 +1565,7 @@ static PyObject *npyiter_multi_index_get(NewNpyArrayIterObject *self)
- }
- 
- static int
--npyiter_multi_index_set(NewNpyArrayIterObject *self, PyObject *value)
-+npyiter_multi_index_set(NewNpyArrayIterObject *self, PyObject *value,void* ignored)
- {
-     npy_intp idim, ndim, multi_index[NPY_MAXDIMS];
- 
-@@ -1620,7 +1620,7 @@ npyiter_multi_index_set(NewNpyArrayIterObject *self, PyObject *value)
-     }
- }
- 
--static PyObject *npyiter_index_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_index_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL || self->finished) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1639,7 +1639,7 @@ static PyObject *npyiter_index_get(NewNpyArrayIterObject *self)
-     }
- }
- 
--static int npyiter_index_set(NewNpyArrayIterObject *self, PyObject *value)
-+static int npyiter_index_set(NewNpyArrayIterObject *self, PyObject *value,void* ignored)
- {
-     if (value == NULL) {
-         PyErr_SetString(PyExc_AttributeError,
-@@ -1678,7 +1678,7 @@ static int npyiter_index_set(NewNpyArrayIterObject *self, PyObject *value)
-     }
- }
- 
--static PyObject *npyiter_iterindex_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_iterindex_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL || self->finished) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1722,7 +1722,7 @@ static int npyiter_iterindex_set(NewNpyArrayIterObject *self, PyObject *value)
-     return 0;
- }
- 
--static PyObject *npyiter_iterrange_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_iterrange_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     npy_intp istart = 0, iend = 0;
-     PyObject *ret;
-@@ -1746,7 +1746,7 @@ static PyObject *npyiter_iterrange_get(NewNpyArrayIterObject *self)
-     return ret;
- }
- 
--static int npyiter_iterrange_set(NewNpyArrayIterObject *self, PyObject *value)
-+static int npyiter_iterrange_set(NewNpyArrayIterObject *self, PyObject *value,void* ignored)
- {
-     npy_intp istart = 0, iend = 0;
- 
-@@ -1788,7 +1788,7 @@ static int npyiter_iterrange_set(NewNpyArrayIterObject *self, PyObject *value)
-     return 0;
- }
- 
--static PyObject *npyiter_has_delayed_bufalloc_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_has_delayed_bufalloc_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1804,7 +1804,7 @@ static PyObject *npyiter_has_delayed_bufalloc_get(NewNpyArrayIterObject *self)
-     }
- }
- 
--static PyObject *npyiter_iterationneedsapi_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_iterationneedsapi_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1820,7 +1820,7 @@ static PyObject *npyiter_iterationneedsapi_get(NewNpyArrayIterObject *self)
-     }
- }
- 
--static PyObject *npyiter_has_multi_index_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_has_multi_index_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1836,7 +1836,7 @@ static PyObject *npyiter_has_multi_index_get(NewNpyArrayIterObject *self)
-     }
- }
- 
--static PyObject *npyiter_has_index_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_has_index_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL) {
-         PyErr_SetString(PyExc_ValueError,
-@@ -1852,7 +1852,7 @@ static PyObject *npyiter_has_index_get(NewNpyArrayIterObject *self)
-     }
- }
- 
--static PyObject *npyiter_dtypes_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_dtypes_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     PyObject *ret;
- 
-@@ -1881,7 +1881,7 @@ static PyObject *npyiter_dtypes_get(NewNpyArrayIterObject *self)
-     return ret;
- }
- 
--static PyObject *npyiter_ndim_get(NewNpyArrayIterObject *self)
-+static PyObject *npyiter_ndim_get(NewNpyArrayIterObject *self,void* ignored)
- {
-     if (self->iter == NULL) {
-         PyErr_SetString(PyExc_ValueError,
-diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
-index 9930f7791..6196b0589 100644
---- a/numpy/core/src/multiarray/scalartypes.c.src
-+++ b/numpy/core/src/multiarray/scalartypes.c.src
-@@ -1079,7 +1079,7 @@ voidtype_flags_get(PyVoidScalarObject *self)
- }
- 
- static PyObject *
--voidtype_dtypedescr_get(PyVoidScalarObject *self)
-+voidtype_dtypedescr_get(PyVoidScalarObject *self,void *NPY_UNUSED(ignored))
- {
-     Py_INCREF(self->descr);
-     return (PyObject *)self->descr;
-@@ -1087,7 +1087,7 @@ voidtype_dtypedescr_get(PyVoidScalarObject *self)
- 
- 
- static PyObject *
--inttype_numerator_get(PyObject *self)
-+inttype_numerator_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     Py_INCREF(self);
-     return self;
-@@ -1109,7 +1109,7 @@ gentype_data_get(PyObject *self)
- 
- 
- static PyObject *
--gentype_itemsize_get(PyObject *self)
-+gentype_itemsize_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     PyArray_Descr *typecode;
-     PyObject *ret;
-@@ -1132,7 +1132,7 @@ static PyObject *
- gentype_sizeof(PyObject *self)
- {
-     Py_ssize_t nbytes;
--    PyObject * isz = gentype_itemsize_get(self);
-+    PyObject * isz = gentype_itemsize_get(self,NULL);
-     if (isz == NULL) {
-         return NULL;
-     }
-@@ -1187,20 +1187,20 @@ gentype_struct_get(PyObject *self)
- }
- 
- static PyObject *
--gentype_priority_get(PyObject *NPY_UNUSED(self))
-+gentype_priority_get(PyObject *NPY_UNUSED(self),void *NPY_UNUSED(ignored))
- {
-     return PyFloat_FromDouble(NPY_SCALAR_PRIORITY);
- }
- 
- static PyObject *
--gentype_shape_get(PyObject *NPY_UNUSED(self))
-+gentype_shape_get(PyObject *NPY_UNUSED(self),void *NPY_UNUSED(ignored))
- {
-     return PyTuple_New(0);
- }
- 
- 
- static PyObject *
--gentype_interface_get(PyObject *self)
-+gentype_interface_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     PyArrayObject *arr;
-     PyObject *inter;
-@@ -1220,20 +1220,20 @@ gentype_interface_get(PyObject *self)
- 
- 
- static PyObject *
--gentype_typedescr_get(PyObject *self)
-+gentype_typedescr_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     return (PyObject *)PyArray_DescrFromScalar(self);
- }
- 
- 
- static PyObject *
--gentype_base_get(PyObject *NPY_UNUSED(self))
-+gentype_base_get(PyObject *NPY_UNUSED(self),void *NPY_UNUSED(ignored))
- {
-     Py_RETURN_NONE;
- }
- 
- static PyObject *
--voidtype_base_get(PyVoidScalarObject *self)
-+voidtype_base_get(PyVoidScalarObject *self,void *NPY_UNUSED(ignored))
- {
-     if (self->base == NULL) {
-         Py_RETURN_NONE;
-@@ -1264,7 +1264,7 @@ _realdescr_fromcomplexscalar(PyObject *self, int *typenum)
- }
- 
- static PyObject *
--gentype_real_get(PyObject *self)
-+gentype_real_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     PyArray_Descr *typecode;
-     PyObject *ret;
-@@ -1291,7 +1291,7 @@ gentype_real_get(PyObject *self)
- }
- 
- static PyObject *
--gentype_imag_get(PyObject *self)
-+gentype_imag_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     PyArray_Descr *typecode=NULL;
-     PyObject *ret;
-@@ -1331,7 +1331,7 @@ gentype_imag_get(PyObject *self)
- }
- 
- static PyObject *
--gentype_flat_get(PyObject *self)
-+gentype_flat_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     PyObject *ret, *arr;
- 
-@@ -1346,7 +1346,7 @@ gentype_flat_get(PyObject *self)
- 
- 
- static PyObject *
--gentype_transpose_get(PyObject *self)
-+gentype_transpose_get(PyObject *self,void *NPY_UNUSED(ignored))
- {
-     Py_INCREF(self);
-     return self;
diff --git a/packages/pillow/meta.yaml b/packages/pillow/meta.yaml
index ea699b4084d..3f989e7a095 100644
--- a/packages/pillow/meta.yaml
+++ b/packages/pillow/meta.yaml
@@ -6,13 +6,12 @@ source:
   url: https://files.pythonhosted.org/packages/8f/7d/1e9c2d8989c209edfd10f878da1af956059a1caab498e5bc34fa11b83f71/Pillow-8.3.1.tar.gz
 
   patches:
-   - patches/setitup.patch
+    - patches/setitup.patch
   extras:
-   -
-      - src/setup.cfg
+    - - src/setup.cfg
       - ./setup.cfg
 build:
   cflags: -s USE_ZLIB=1 -s USE_LIBJPEG=1 -s USE_FREETYPE=1
 test:
   imports:
-  - PIL
+    - PIL


Code review comments:
diff_hunk: @@ -23,7 +25,11 @@ def test_fnmatch(selenium_module_scope, pattern, name, flags, expected):
     assert result == expected
 
 
-@run_in_pyodide(packages=["cffi_example"], module_scope=True)
+@run_in_pyodide(
+    packages=["cffi_example"],
+    module_scope=True,
+    xfail_browsers={"chrome": "Doesn't work in chrome v90"},
path: packages/cffi_example/test_cffi_example.py
text: @user1:
But it works locally for you with a different chrome version? or it doesn't work in chrome altogether?

@author:
It works locally on chrome 91 and chrome 96. Breaks locally on Chrome 90.

@author:
I added a more specific description.