1
0
forked from Mirror/wren

Reset the API stack after a foreign constructor returns.

This commit is contained in:
Bob Nystrom
2016-08-28 08:23:27 -07:00
parent d331cbf43d
commit e7cabbb5e4
6 changed files with 82 additions and 1 deletions

View File

@ -12,6 +12,7 @@
#include "handle.h"
#include "lists.h"
#include "new_vm.h"
#include "reset_stack_after_foreign_construct.h"
#include "slots.h"
// The name of the currently executing API test.
@ -73,9 +74,11 @@ static WrenForeignClassMethods bindForeignClass(
foreignClassBindClass(className, &methods);
if (methods.allocate != NULL) return methods;
slotsBindClass(className, &methods);
resetStackAfterForeignConstructBindClass(className, &methods);
if (methods.allocate != NULL) return methods;
slotsBindClass(className, &methods);
if (methods.allocate != NULL) return methods;
fprintf(stderr,
"Unknown foreign class '%s' for test '%s'\n", className, testName);
@ -85,6 +88,10 @@ static WrenForeignClassMethods bindForeignClass(
static void afterLoad(WrenVM* vm) {
if (strstr(testName, "/call.wren") != NULL) callRunTests(vm);
if (strstr(testName, "/reset_stack_after_foreign_construct.wren") != NULL)
{
resetStackAfterForeignConstructRunTests(vm);
}
}
int main(int argc, const char* argv[])

View File

@ -0,0 +1,44 @@
#include <stdio.h>
#include <string.h>
#include "foreign_class.h"
static void counterAllocate(WrenVM* vm)
{
double* counter = (double*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(double));
*counter = wrenGetSlotDouble(vm, 1);
}
void resetStackAfterForeignConstructBindClass(
const char* className, WrenForeignClassMethods* methods)
{
if (strcmp(className, "ResetStackForeign") == 0)
{
methods->allocate = counterAllocate;
return;
}
}
void resetStackAfterForeignConstructRunTests(WrenVM* vm)
{
wrenEnsureSlots(vm, 1);
wrenGetVariable(vm, "main", "Test", 0);
WrenHandle* testClass = wrenGetSlotHandle(vm, 0);
WrenHandle* callConstruct = wrenMakeCallHandle(vm, "callConstruct()");
WrenHandle* afterConstruct = wrenMakeCallHandle(vm, "afterConstruct(_,_)");
wrenEnsureSlots(vm, 1);
wrenSetSlotHandle(vm, 0, testClass);
wrenCall(vm, callConstruct);
wrenEnsureSlots(vm, 3);
wrenSetSlotHandle(vm, 0, testClass);
wrenSetSlotDouble(vm, 1, 1.0);
wrenSetSlotDouble(vm, 2, 2.0);
wrenCall(vm, afterConstruct);
wrenReleaseHandle(vm, testClass);
wrenReleaseHandle(vm, callConstruct);
wrenReleaseHandle(vm, afterConstruct);
}

View File

@ -0,0 +1,5 @@
#include "wren.h"
void resetStackAfterForeignConstructBindClass(
const char* className, WrenForeignClassMethods* methods);
void resetStackAfterForeignConstructRunTests(WrenVM* vm);

View File

@ -0,0 +1,18 @@
// Regression test.
//
// After a foreign constructor was called, it did not reset the API stack. If
// you tried to immediately reuse the API stack by calling wrenCall(), it
// would be in a broken state.
foreign class ResetStackForeign {
construct new(a) {}
}
class Test {
static callConstruct() {
ResetStackForeign.new(1)
}
static afterConstruct(a, b) {
System.print(a + b) // expect: 3
}
}