shithub: libmujs

Download patch

ref: 6c8400d872634c40ca072d94696eadf0d87c9393
parent: 26cde86041665b800d807fa30f64eb96dd54e71b
author: Tor Andersson <tor@ccxvii.net>
date: Mon Jan 20 18:14:48 EST 2014

Fix CFunction calling conventions.

'this' is always argument 0 (even for constructors, where it is null).
argc is the number of real arguments (not counting the 'this' object).

for (i = 1; i <= argc; ++i)
	js_toXXX(J, i);

--- a/jsbarray.c
+++ b/jsbarray.c
@@ -2,10 +2,10 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int jsB_Array(js_State *J, int n) { return 0; }
-static int jsB_new_Array(js_State *J, int n) { return 0; }
+static int jsB_Array(js_State *J, int argc) { return 0; }
+static int jsB_new_Array(js_State *J, int argc) { return 0; }
 
-static int A_isArray(js_State *J, int n)
+static int A_isArray(js_State *J, int argc)
 {
 	if (js_isobject(J, 1)) {
 		js_Object *T = js_toobject(J, 1);
--- a/jsbboolean.c
+++ b/jsbboolean.c
@@ -2,19 +2,19 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int jsB_new_Boolean(js_State *J, int n)
+static int jsB_new_Boolean(js_State *J, int argc)
 {
-	js_newboolean(J, js_toboolean(J, 0));
+	js_newboolean(J, js_toboolean(J, 1));
 	return 1;
 }
 
-static int jsB_Boolean(js_State *J, int n)
+static int jsB_Boolean(js_State *J, int argc)
 {
 	js_pushboolean(J, js_toboolean(J, 1));
 	return 1;
 }
 
-static int Bp_toString(js_State *J, int n)
+static int Bp_toString(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
@@ -22,7 +22,7 @@
 	return 1;
 }
 
-static int Bp_valueOf(js_State *J, int n)
+static int Bp_valueOf(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CBOOLEAN) js_typeerror(J, "not a boolean");
--- a/jsberror.c
+++ b/jsberror.c
@@ -5,7 +5,7 @@
 #define QQ(X) #X
 #define Q(X) QQ(X)
 
-static int Ep_toString(js_State *J, int n)
+static int Ep_toString(js_State *J, int argc)
 {
 	js_getproperty(J, 0, "name");
 	js_pushliteral(J, ": ");
@@ -16,17 +16,9 @@
 }
 
 #define DECL(NAME) \
-	static int jsB_new_##NAME(js_State *J, int n) { \
+	static int jsB_##NAME(js_State *J, int argc) { \
 		js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
-		if (n > 0) { \
-			js_pushstring(J, js_tostring(J, 0)); \
-			js_setproperty(J, -2, "message"); \
-		} \
-		return 1; \
-	} \
-	static int jsB_##NAME(js_State *J, int n) { \
-		js_pushobject(J, jsV_newobject(J, JS_CERROR, J->NAME##_prototype)); \
-		if (n > 1) { \
+		if (argc > 0) { \
 			js_pushstring(J, js_tostring(J, 1)); \
 			js_setproperty(J, -2, "message"); \
 		} \
@@ -49,13 +41,13 @@
 			jsB_props(J, "message", "an error has occurred");
 			jsB_propf(J, "toString", Ep_toString, 0);
 	}
-	js_newcconstructor(J, jsB_Error, jsB_new_Error);
+	js_newcconstructor(J, jsB_Error, jsB_Error);
 	js_setglobal(J, "Error");
 
 	#define INIT(NAME) \
 		js_pushobject(J, J->NAME##_prototype); \
 		jsB_props(J, "name", Q(NAME)); \
-		js_newcconstructor(J, jsB_##NAME, jsB_new_##NAME); \
+		js_newcconstructor(J, jsB_##NAME, jsB_##NAME); \
 		js_setglobal(J, Q(NAME));
 
 	INIT(EvalError);
--- a/jsbfunction.c
+++ b/jsbfunction.c
@@ -3,16 +3,16 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int jsB_new_Function(js_State *J, int n) { return 0; }
-static int jsB_Function(js_State *J, int n) { return 0; }
+static int jsB_new_Function(js_State *J, int argc) { return 0; }
+static int jsB_Function(js_State *J, int argc) { return 0; }
 
-static int jsB_Function_prototype(js_State *J, int n)
+static int jsB_Function_prototype(js_State *J, int argc)
 {
 	js_pushundefined(J);
 	return 1;
 }
 
-static int Fp_toString(js_State *J, int nargs)
+static int Fp_toString(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	char *s;
@@ -45,9 +45,9 @@
 	return 1;
 }
 
-static int Fp_apply(js_State *J, int n)
+static int Fp_apply(js_State *J, int argc)
 {
-	int i, argc;
+	int i, n;
 	char name[20];
 
 	if (!js_iscallable(J, 0))
@@ -57,19 +57,19 @@
 	js_copy(J, 1);
 
 	js_getproperty(J, 2, "length");
-	argc = js_tonumber(J, -1);
+	n = js_tonumber(J, -1);
 	js_pop(J, 1);
 
-	for (i = 0; i < argc; ++i) {
+	for (i = 0; i < n; ++i) {
 		sprintf(name, "%d", i);
 		js_getproperty(J, 2, name);
 	}
 
-	js_call(J, argc);
+	js_call(J, n);
 	return 1;
 }
 
-static int Fp_call(js_State *J, int n)
+static int Fp_call(js_State *J, int argc)
 {
 	int i;
 
@@ -78,11 +78,10 @@
 
 	js_copy(J, 0);
 	js_copy(J, 1);
+	for (i = 2; i <= argc; ++i)
+		js_copy(J, i);
 
-	for (i = 1; i < n; ++i)
-		js_copy(J, i + 1);
-
-	js_call(J, n - 1);
+	js_call(J, argc - 1);
 	return 1;
 }
 
--- a/jsbmath.c
+++ b/jsbmath.c
@@ -2,60 +2,60 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int Math_abs(js_State *J, int nargs) {
+static int Math_abs(js_State *J, int argc) {
 	return js_pushnumber(J, abs(js_tonumber(J, 1))), 1;
 }
-static int Math_acos(js_State *J, int nargs) {
+static int Math_acos(js_State *J, int argc) {
 	return js_pushnumber(J, acos(js_tonumber(J, 1))), 1;
 }
-static int Math_asin(js_State *J, int nargs) {
+static int Math_asin(js_State *J, int argc) {
 	return js_pushnumber(J, asin(js_tonumber(J, 1))), 1;
 }
-static int Math_atan(js_State *J, int nargs) {
+static int Math_atan(js_State *J, int argc) {
 	return js_pushnumber(J, atan(js_tonumber(J, 1))), 1;
 }
-static int Math_atan2(js_State *J, int nargs) {
+static int Math_atan2(js_State *J, int argc) {
 	return js_pushnumber(J, atan2(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
 }
-static int Math_ceil(js_State *J, int nargs) {
+static int Math_ceil(js_State *J, int argc) {
 	return js_pushnumber(J, ceil(js_tonumber(J, 1))), 1;
 }
-static int Math_cos(js_State *J, int nargs) {
+static int Math_cos(js_State *J, int argc) {
 	return js_pushnumber(J, cos(js_tonumber(J, 1))), 1;
 }
-static int Math_exp(js_State *J, int nargs) {
+static int Math_exp(js_State *J, int argc) {
 	return js_pushnumber(J, exp(js_tonumber(J, 1))), 1;
 }
-static int Math_floor(js_State *J, int nargs) {
+static int Math_floor(js_State *J, int argc) {
 	return js_pushnumber(J, floor(js_tonumber(J, 1))), 1;
 }
-static int Math_log(js_State *J, int nargs) {
+static int Math_log(js_State *J, int argc) {
 	return js_pushnumber(J, log(js_tonumber(J, 1))), 1;
 }
-static int Math_pow(js_State *J, int nargs) {
+static int Math_pow(js_State *J, int argc) {
 	return js_pushnumber(J, pow(js_tonumber(J, 1), js_tonumber(J, 2))), 1;
 }
-static int Math_random(js_State *J, int nargs) {
+static int Math_random(js_State *J, int argc) {
 	return js_pushnumber(J, (double)rand() / (RAND_MAX - 1)), 1;
 }
-static int Math_round(js_State *J, int nargs) {
+static int Math_round(js_State *J, int argc) {
 	return js_pushnumber(J, round(js_tonumber(J, 1))), 1;
 }
-static int Math_sin(js_State *J, int nargs) {
+static int Math_sin(js_State *J, int argc) {
 	return js_pushnumber(J, sin(js_tonumber(J, 1))), 1;
 }
-static int Math_sqrt(js_State *J, int nargs) {
+static int Math_sqrt(js_State *J, int argc) {
 	return js_pushnumber(J, sqrt(js_tonumber(J, 1))), 1;
 }
-static int Math_tan(js_State *J, int nargs) {
+static int Math_tan(js_State *J, int argc) {
 	return js_pushnumber(J, tan(js_tonumber(J, 1))), 1;
 }
 
-static int Math_max(js_State *J, int nargs)
+static int Math_max(js_State *J, int argc)
 {
 	double n = js_tonumber(J, 1);
 	int i;
-	for (i = 2; i < nargs; i++) {
+	for (i = 2; i <= argc; ++i) {
 		double m = js_tonumber(J, i);
 		n = n > m ? n : m;
 	}
@@ -63,11 +63,11 @@
 	return 1;
 }
 
-static int Math_min(js_State *J, int nargs)
+static int Math_min(js_State *J, int argc)
 {
 	double n = js_tonumber(J, 1);
 	int i;
-	for (i = 2; i < nargs; i++) {
+	for (i = 2; i <= argc; ++i) {
 		double m = js_tonumber(J, i);
 		n = n < m ? n : m;
 	}
--- a/jsbnumber.c
+++ b/jsbnumber.c
@@ -2,19 +2,19 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int jsB_new_Number(js_State *J, int n)
+static int jsB_new_Number(js_State *J, int argc)
 {
-	js_newnumber(J, n > 0 ? js_tonumber(J, 0) : 0);
+	js_newnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
 	return 1;
 }
 
-static int jsB_Number(js_State *J, int n)
+static int jsB_Number(js_State *J, int argc)
 {
-	js_pushnumber(J, n > 0 ? js_tonumber(J, 1) : 0);
+	js_pushnumber(J, argc > 0 ? js_tonumber(J, 1) : 0);
 	return 1;
 }
 
-static int Np_valueOf(js_State *J, int n)
+static int Np_valueOf(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
@@ -22,7 +22,7 @@
 	return 1;
 }
 
-static int Np_toString(js_State *J, int n)
+static int Np_toString(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CNUMBER) js_typeerror(J, "not a number");
@@ -30,7 +30,7 @@
 	return 1;
 }
 
-static int Np_toFixed(js_State *J, int n)
+static int Np_toFixed(js_State *J, int argc)
 {
 	char buf[40];
 	js_Object *self = js_toobject(J, 0);
@@ -41,7 +41,7 @@
 	return 1;
 }
 
-static int Np_toExponential(js_State *J, int n)
+static int Np_toExponential(js_State *J, int argc)
 {
 	char buf[40];
 	js_Object *self = js_toobject(J, 0);
@@ -52,7 +52,7 @@
 	return 1;
 }
 
-static int Np_toPrecision(js_State *J, int n)
+static int Np_toPrecision(js_State *J, int argc)
 {
 	char buf[40];
 	js_Object *self = js_toobject(J, 0);
--- a/jsbobject.c
+++ b/jsbobject.c
@@ -2,18 +2,18 @@
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int jsB_new_Object(js_State *J, int n)
+static int jsB_new_Object(js_State *J, int argc)
 {
-	if (n == 0 || js_isundefined(J, 0) || js_isnull(J, 0))
+	if (argc == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
 		js_newobject(J);
 	else
-		js_pushobject(J, js_toobject(J, 0));
+		js_pushobject(J, js_toobject(J, 1));
 	return 1;
 }
 
-static int jsB_Object(js_State *J, int n)
+static int jsB_Object(js_State *J, int argc)
 {
-	if (n == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
+	if (argc == 0 || js_isundefined(J, 1) || js_isnull(J, 1))
 		js_newobject(J);
 	else
 		js_pushobject(J, js_toobject(J, 1));
@@ -20,7 +20,7 @@
 	return 1;
 }
 
-static int Op_toString(js_State *J, int n)
+static int Op_toString(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	switch (self->type) {
@@ -41,13 +41,13 @@
 	return 1;
 }
 
-static int Op_valueOf(js_State *J, int n)
+static int Op_valueOf(js_State *J, int argc)
 {
 	/* return the 'this' object */
 	return 1;
 }
 
-static int Op_hasOwnProperty(js_State *J, int n)
+static int Op_hasOwnProperty(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	const char *name = js_tostring(J, 1);
@@ -56,7 +56,7 @@
 	return 1;
 }
 
-static int Op_isPrototypeOf(js_State *J, int n)
+static int Op_isPrototypeOf(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (js_isobject(J, 1)) {
@@ -73,7 +73,7 @@
 	return 1;
 }
 
-static int Op_propertyIsEnumerable(js_State *J, int n)
+static int Op_propertyIsEnumerable(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	const char *name = js_tostring(J, 1);
--- a/jsbstring.c
+++ b/jsbstring.c
@@ -3,19 +3,19 @@
 #include "jsbuiltin.h"
 #include "jsutf.h"
 
-static int jsB_new_String(js_State *J, int n)
+static int jsB_new_String(js_State *J, int argc)
 {
-	js_newstring(J, n > 0 ? js_tostring(J, 0) : "");
+	js_newstring(J, argc > 0 ? js_tostring(J, 1) : "");
 	return 1;
 }
 
-static int jsB_String(js_State *J, int n)
+static int jsB_String(js_State *J, int argc)
 {
-	js_pushliteral(J, n > 0 ? js_tostring(J, 1) : "");
+	js_pushliteral(J, argc > 0 ? js_tostring(J, 1) : "");
 	return 1;
 }
 
-static int Sp_toString(js_State *J, int n)
+static int Sp_toString(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
@@ -23,7 +23,7 @@
 	return 1;
 }
 
-static int Sp_valueOf(js_State *J, int n)
+static int Sp_valueOf(js_State *J, int argc)
 {
 	js_Object *self = js_toobject(J, 0);
 	if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
@@ -46,7 +46,7 @@
 	return rune;
 }
 
-static int Sp_charAt(js_State *J, int n)
+static int Sp_charAt(js_State *J, int argc)
 {
 	char buf[UTFmax + 1];
 	const char *s = js_tostring(J, 0);
@@ -61,7 +61,7 @@
 	return 1;
 }
 
-static int Sp_charCodeAt(js_State *J, int n)
+static int Sp_charCodeAt(js_State *J, int argc)
 {
 	const char *s = js_tostring(J, 0);
 	int pos = js_tointeger(J, 1);
@@ -73,13 +73,13 @@
 	return 1;
 }
 
-static int S_fromCharCode(js_State *J, int n)
+static int S_fromCharCode(js_State *J, int argc)
 {
 	int i;
 	Rune c;
-	char *s = malloc(n * UTFmax + 1), *p = s;
+	char *s = malloc(argc * UTFmax + 1), *p = s;
 	// TODO: guard malloc with try/catch
-	for (i = 0; i < n; i++) {
+	for (i = 0; i <= argc; ++i) {
 		c = js_tointeger(J, i + 1); // TODO: ToUInt16()
 		p += runetochar(p, &c);
 	}
@@ -99,6 +99,18 @@
 		jsB_propf(J, "valueOf", Sp_valueOf, 0);
 		jsB_propf(J, "charAt", Sp_charAt, 1);
 		jsB_propf(J, "charCodeAt", Sp_charCodeAt, 1);
+		//jsB_propf(J, "concat", Sp_concat, 1);
+		//jsB_propf(J, "indexOf", Sp_indexOf, 1);
+		//jsB_propf(J, "lastIndexOf", Sp_lastIndexOf, 1);
+		//jsB_propf(J, "localeCompare", Sp_localeCompare, 1);
+		//jsB_propf(J, "slice", Sp_slice, 2);
+		// match (uses regexp)
+		// replace (uses regexp)
+		// search (uses regexp)
+		// split (uses regexp)
+		//jsB_propf(J, "substring", Sp_substring, 2);
+		//jsB_propf(J, "toLowerCase", Sp_toLowerCase, 0);
+		//jsB_propf(J, "toUpperCase", Sp_toUpperCase, 0);
 	}
 	js_newcconstructor(J, jsB_String, jsB_new_String);
 	{
--- a/jsbuiltin.c
+++ b/jsbuiltin.c
@@ -5,7 +5,7 @@
 static int jsB_print(js_State *J, int argc)
 {
 	int i;
-	for (i = 1; i < argc; ++i) {
+	for (i = 1; i <= argc; ++i) {
 		const char *s = js_tostring(J, i);
 		if (i > 1) putchar(' ');
 		fputs(s, stdout);
--- a/jsrun.c
+++ b/jsrun.c
@@ -188,6 +188,10 @@
 void js_pop(js_State *J, int n)
 {
 	TOP -= n;
+	if (TOP < BOT) {
+		TOP = BOT;
+		js_error(J, "stack underflow!");
+	}
 }
 
 void js_copy(js_State *J, int idx)
@@ -389,7 +393,7 @@
 
 static void jsR_callcfunction(js_State *J, int n, js_CFunction F)
 {
-	int rv = F(J, n + 1);
+	int rv = F(J, n);
 	if (rv) {
 		js_Value v = js_tovalue(J, -1);
 		TOP = --BOT; /* pop down to below function */
@@ -422,10 +426,13 @@
 	js_Object *prototype;
 	js_Object *newobj;
 
-	/* built-in constructors create their own objects */
+	/* built-in constructors create their own objects, give them a 'null' this */
 	if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) {
 		int savebot = BOT;
-		BOT = TOP - n;
+		js_pushnull(J);
+		if (n > 0)
+			js_rot(J, n + 1);
+		BOT = TOP - n - 1;
 		jsR_callcfunction(J, n, obj->u.c.constructor);
 		BOT = savebot;
 		return;