This commit is contained in:
Brendan Eich 2008-09-17 06:17:50 +01:00
commit 0811a8b28f
8 changed files with 136 additions and 49 deletions

View File

@ -2041,41 +2041,31 @@ array_sort(JSContext *cx, uintN argc, jsval *vp)
/*
* Perl-inspired push, pop, shift, unshift, and splice methods.
*/
static JSBool
array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *vp)
JSBool
js_array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsuint length, newlength;
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
newlength = length + argc;
if (!InitArrayElements(cx, obj, length, newlength, vp + 2))
if (!InitArrayElements(cx, obj, length, newlength, argv))
return JS_FALSE;
/* Per ECMA-262, return the new array length. */
if (!IndexToValue(cx, newlength, vp))
if (!IndexToValue(cx, newlength, rval))
return JS_FALSE;
return js_SetLengthProperty(cx, obj, newlength);
}
static JSBool
array_push(JSContext *cx, uintN argc, jsval *vp)
JSBool
js_array_push1_dense(JSContext* cx, JSObject* obj, jsval v, jsval *rval)
{
JSObject *obj;
uint32 length;
/* Insist on one argument and obj of the expected class. */
obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
if (argc != 1 || !OBJ_IS_DENSE_ARRAY(cx, obj))
return array_push_slowly(cx, obj, argc, vp);
length = obj->fslots[JSSLOT_ARRAY_LENGTH];
uint32 length = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (INDEX_TOO_SPARSE(obj, length)) {
if (!js_MakeArraySlow(cx, obj))
return JS_FALSE;
return array_push_slowly(cx, obj, argc, vp);
return js_array_push_slowly(cx, obj, 1, &v, rval);
}
if (!EnsureLength(cx, obj, length + 1))
@ -2084,34 +2074,30 @@ array_push(JSContext *cx, uintN argc, jsval *vp)
JS_ASSERT(obj->dslots[length] == JSVAL_HOLE);
obj->fslots[JSSLOT_ARRAY_COUNT]++;
obj->dslots[length] = vp[2];
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], vp);
obj->dslots[length] = v;
return IndexToValue(cx, obj->fslots[JSSLOT_ARRAY_LENGTH], rval);
}
JSBool
array_pop(JSContext *cx, uintN argc, jsval *vp)
js_array_push(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
jsuint index;
JSBool hole;
/* Insist on one argument and obj of the expected class. */
obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
if (OBJ_IS_DENSE_ARRAY(cx, obj)) {
index = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (index == 0) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
index--;
if (!GetArrayElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index))
return JS_FALSE;
obj->fslots[JSSLOT_ARRAY_LENGTH] = index;
return JS_TRUE;
}
if (argc != 1 || !OBJ_IS_DENSE_ARRAY(cx, obj))
return js_array_push_slowly(cx, obj, argc, vp + 2, vp);
return js_array_push1_dense(cx, obj, vp[2], vp);
}
JSBool
js_array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp)
{
jsuint index;
JSBool hole;
if (!js_GetLengthProperty(cx, obj, &index))
return JS_FALSE;
@ -2129,6 +2115,40 @@ array_pop(JSContext *cx, uintN argc, jsval *vp)
return js_SetLengthProperty(cx, obj, index);
}
JSBool
js_array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp)
{
jsuint index;
JSBool hole;
index = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (index == 0) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
index--;
if (!GetArrayElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index))
return JS_FALSE;
obj->fslots[JSSLOT_ARRAY_LENGTH] = index;
return JS_TRUE;
}
JSBool
js_array_pop(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
if (OBJ_IS_DENSE_ARRAY(cx, obj))
return js_array_pop_dense(cx, obj, vp);
return js_array_pop_slowly(cx, obj, vp);
}
static JSBool
array_shift(JSContext *cx, uintN argc, jsval *vp)
{
@ -2884,8 +2904,8 @@ static JSFunctionSpec array_methods[] = {
JS_FN("join", js_array_join, 1,JSFUN_GENERIC_NATIVE),
JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE),
JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE),
JS_FN("push", array_push, 1,JSFUN_GENERIC_NATIVE),
JS_FN("pop", array_pop, 0,JSFUN_GENERIC_NATIVE),
JS_FN("push", js_array_push, 1,JSFUN_GENERIC_NATIVE),
JS_FN("pop", js_array_pop, 0,JSFUN_GENERIC_NATIVE),
JS_FN("shift", array_shift, 0,JSFUN_GENERIC_NATIVE),
JS_FN("unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE),
JS_FN("splice", array_splice, 2,JSFUN_GENERIC_NATIVE),

View File

@ -134,6 +134,24 @@ js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
extern JSBool
js_array_join(JSContext *cx, uintN argc, jsval *vp);
extern JSBool
js_array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
extern JSBool
js_array_push1_dense(JSContext *cx, JSObject *obj, jsval v, jsval *rval);
extern JSBool
js_array_push(JSContext *cx, uintN argc, jsval *vp);
extern JSBool
js_array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp);
extern JSBool
js_array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp);
extern JSBool
js_array_pop(JSContext *cx, uintN argc, jsval *vp);
enum ArrayToStringOp {
TO_STRING,
TO_LOCALE_STRING,

View File

@ -246,6 +246,29 @@ js_Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
return JSVAL_TO_STRING(v);
}
jsval FASTCALL
js_Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
{
if (!(OBJ_IS_DENSE_ARRAY(cx, obj)
? js_array_push1_dense(cx, obj, v, &v)
: js_array_push_slowly(cx, obj, 1, &v, &v))) {
return JSVAL_ERROR_COOKIE;
}
return v;
}
jsval FASTCALL
js_Array_p_pop(JSContext* cx, JSObject* obj)
{
jsval v;
if (!(OBJ_IS_DENSE_ARRAY(cx, obj)
? js_array_pop_dense(cx, obj, &v)
: js_array_pop_slowly(cx, obj, &v))) {
return JSVAL_ERROR_COOKIE;
}
return v;
}
JSString* FASTCALL
js_String_p_substring(JSContext* cx, JSString* str, jsint begin, jsint end)
{
@ -601,11 +624,6 @@ js_FastNewObject(JSContext* cx, JSObject* ctor)
JSClass* clasp = FUN_INTERPRETED(fun) ? &js_ObjectClass : fun->u.n.clasp;
JS_ASSERT(clasp != &js_ArrayClass);
JS_ASSERT(JS_ON_TRACE(cx));
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
if (!obj)
return NULL;
JS_LOCK_OBJ(cx, ctor);
JSScope *scope = OBJ_SCOPE(ctor);
JS_ASSERT(scope->object == ctor);
@ -616,8 +634,20 @@ js_FastNewObject(JSContext* cx, JSObject* ctor)
jsval v = LOCKED_OBJ_GET_SLOT(ctor, sprop->slot);
JS_UNLOCK_SCOPE(cx, scope);
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
JSObject* proto = JSVAL_TO_OBJECT(v);
JSObject* proto;
if (JSVAL_IS_PRIMITIVE(v)) {
if (!js_GetClassPrototype(cx, JSVAL_TO_OBJECT(ctor->fslots[JSSLOT_PARENT]),
INT_TO_JSID(JSProto_Object), &proto)) {
return NULL;
}
} else {
proto = JSVAL_TO_OBJECT(v);
}
JS_ASSERT(JS_ON_TRACE(cx));
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
if (!obj)
return NULL;
obj->classword = jsuword(clasp);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);

View File

@ -51,6 +51,7 @@
#include <alloca.h>
#endif
#define AVMPLUS_DEFINE_NEW_DELETE
#include "nanojit/avmplus.h" // nanojit
#include "nanojit/nanojit.h"
#include "jsarray.h" // higher-level library and API headers
@ -3653,7 +3654,6 @@ TraceRecorder::getThis(LIns*& this_ins)
this_ins = get(&cx->fp->argv[-1]);
guard(false, lir->ins_eq0(this_ins), MISMATCH_EXIT);
} else { /* in global code */
JS_ASSERT(!JSVAL_IS_NULL(cx->fp->argv[-1]));
this_ins = scopeChain();
}
return true;
@ -3743,7 +3743,7 @@ TraceRecorder::record_EnterFrame()
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
jsval* vp = &fp->argv[fp->argc];
jsval* vpstop = vp + (fp->fun->nargs - fp->argc);
jsval* vpstop = vp + ptrdiff_t(fp->fun->nargs) - ptrdiff_t(fp->argc);
if (applyingArguments) {
applyingArguments = false;
while (vp < vpstop) {

View File

@ -38,6 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
#define AVMPLUS_DEFINE_NEW_DELETE
#include "nanojit.h"
namespace nanojit

View File

@ -36,7 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
#define AVMPLUS_DEFINE_NEW_DELETE
#include "nanojit.h"
#include <stdio.h>

View File

@ -316,6 +316,7 @@ public:
}
};
#ifdef AVMPLUS_DEFINE_NEW_DELETE
inline void*
operator new(size_t size, GC* gc)
{
@ -327,6 +328,7 @@ operator delete(void* p)
{
free(p);
}
#endif
#define DWB(x) x
#define DRCWB(x) x

View File

@ -1332,6 +1332,22 @@ this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
testGlobalProtoAccess.expected = "ok";
test(testGlobalProtoAccess);
function testSetPropNeitherMissNorHit() {
for (var j = 0; j < 5; ++j) { if (({}).__proto__ = 1) { } }
return "ok";
}
testSetPropNeitherMissNorHit.expected = "ok";
test(testSetPropNeitherMissNorHit);
function testPrimitiveConstructorPrototype() {
var f = function(){};
f.prototype = false;
for (let j=0;j<5;++j) { new f; }
return "ok";
}
testPrimitiveConstructorPrototype.expected = "ok";
test(testPrimitiveConstructorPrototype);
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
print("\npassed:", passes.length && passes.join(","));
print("\nFAILED:", fails.length && fails.join(","));