📄 jsiter.c
字号:
JSITER_KEYVALUE))); /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT(!(flags & JSITER_KEYVALUE) || (flags & JSITER_FOREACH)); /* XXX work around old valueOf call hidden beneath js_ValueToObject */ if (!JSVAL_IS_PRIMITIVE(*vp)) { obj = JSVAL_TO_OBJECT(*vp); } else { /* * Enumerating over null and undefined gives an empty enumerator. * This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of * the first production in 12.6.4 and step 4 of the second production, * but it's "web JS" compatible. */ if ((flags & JSITER_ENUMERATE)) { if (!js_ValueToObject(cx, *vp, &obj)) return JS_FALSE; if (!obj) goto default_iter; } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) return JS_FALSE; } } JS_ASSERT(obj); JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); atom = cx->runtime->atomState.iteratorAtom;#if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, obj)) { if (!js_GetXMLFunction(cx, obj, ATOM_TO_JSID(atom), vp)) goto bad; } else#endif { if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(atom), vp)) goto bad; } if (JSVAL_IS_VOID(*vp)) { default_iter: /* * Fail over to the default enumerating native iterator. * * Create iterobj with a NULL parent to ensure that we use the correct * scope chain to lookup the iterator's constructor. Since we use the * parent slot to keep track of the iterable, we must fix it up after. */ iterobj = js_NewObject(cx, &js_IteratorClass, NULL, NULL); if (!iterobj) goto bad; /* Store iterobj in *vp to protect it from GC (callers must root vp). */ *vp = OBJECT_TO_JSVAL(iterobj); if (!InitNativeIterator(cx, iterobj, obj, flags)) goto bad; } else { arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); if (!js_InternalInvoke(cx, obj, *vp, JSINVOKE_ITERATOR, 1, &arg, vp)) goto bad; if (JSVAL_IS_PRIMITIVE(*vp)) { str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, *vp, NULL); if (str) { JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ITERATOR_RETURN, JSSTRING_CHARS(str), JSSTRING_CHARS(ATOM_TO_STRING(atom))); } goto bad; } } ok = JS_TRUE; out: if (obj) JS_POP_TEMP_ROOT(cx, &tvr); return ok; bad: ok = JS_FALSE; goto out;}static JSBoolCallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval){ JSObject *obj, *origobj; jsval state; JSBool foreach; jsid id; JSObject *obj2; JSBool cond; JSClass *clasp; JSExtendedClass *xclasp; JSProperty *prop; JSString *str; JS_ASSERT(flags & JSITER_ENUMERATE); JS_ASSERT(JSVAL_TO_PRIVATE(iterobj->slots[JSSLOT_CLASS]) == &js_IteratorClass); obj = JSVAL_TO_OBJECT(iterobj->slots[JSSLOT_PARENT]); origobj = JSVAL_TO_OBJECT(iterobj->slots[JSSLOT_PROTO]); state = iterobj->slots[JSSLOT_ITER_STATE]; if (JSVAL_IS_NULL(state)) goto stop; foreach = (flags & JSITER_FOREACH) != 0;#if JS_HAS_XML_SUPPORT /* * Treat an XML object specially only when it starts the prototype chain. * Otherwise we need to do the usual deleted and shadowed property checks. */ if (obj == origobj && OBJECT_IS_XML(cx, obj)) { if (foreach) { JSXMLObjectOps *xmlops = (JSXMLObjectOps *) obj->map->ops; if (!xmlops->enumerateValues(cx, obj, JSENUMERATE_NEXT, &state, &id, rval)) { return JS_FALSE; } } else { if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id)) return JS_FALSE; } iterobj->slots[JSSLOT_ITER_STATE] = state; if (JSVAL_IS_NULL(state)) goto stop; } else#endif { restart: if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &state, &id)) return JS_TRUE; iterobj->slots[JSSLOT_ITER_STATE] = state; if (JSVAL_IS_NULL(state)) {#if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, obj)) { /* * We just finished enumerating an XML obj that is present on * the prototype chain of a non-XML origobj. Stop further * prototype chain searches because XML objects don't * enumerate prototypes. */ JS_ASSERT(origobj != obj); JS_ASSERT(!OBJECT_IS_XML(cx, origobj)); } else#endif { obj = OBJ_GET_PROTO(cx, obj); if (obj) { iterobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj); if (!OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &state, NULL)) return JS_FALSE; iterobj->slots[JSSLOT_ITER_STATE] = state; if (!JSVAL_IS_NULL(state)) goto restart; } } goto stop; } /* Skip properties not in obj when looking from origobj. */ if (!OBJ_LOOKUP_PROPERTY(cx, origobj, id, &obj2, &prop)) return JS_FALSE; if (!prop) goto restart; OBJ_DROP_PROPERTY(cx, obj2, prop); /* * If the id was found in a prototype object or an unrelated object * (specifically, not in an inner object for obj), skip it. This step * means that all OBJ_LOOKUP_PROPERTY implementations must return an * object further along on the prototype chain, or else possibly an * object returned by the JSExtendedClass.outerObject optional hook. */ if (obj != obj2) { cond = JS_FALSE; clasp = OBJ_GET_CLASS(cx, obj2); if (clasp->flags & JSCLASS_IS_EXTENDED) { xclasp = (JSExtendedClass *) clasp; cond = xclasp->outerObject && xclasp->outerObject(cx, obj2) == obj; } if (!cond) goto restart; } if (foreach) { /* Get property querying the original object. */ if (!OBJ_GET_PROPERTY(cx, origobj, id, rval)) return JS_FALSE; } } if (foreach) { if (flags & JSITER_KEYVALUE) { if (!NewKeyValuePair(cx, id, *rval, rval)) return JS_FALSE; } } else { /* Make rval a string for uniformity and compatibility. */ if (JSID_IS_ATOM(id)) { *rval = ATOM_KEY(JSID_TO_ATOM(id)); }#if JS_HAS_XML_SUPPORT else if (JSID_IS_OBJECT(id)) { str = js_ValueToString(cx, OBJECT_JSID_TO_JSVAL(id)); if (!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); }#endif else { str = js_NumberToString(cx, (jsdouble)JSID_TO_INT(id)); if (!str) return JS_FALSE; *rval = STRING_TO_JSVAL(str); } } return JS_TRUE; stop: JS_ASSERT(iterobj->slots[JSSLOT_ITER_STATE] == JSVAL_NULL); *rval = JSVAL_HOLE; return JS_TRUE;}JSBooljs_CallIteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval){ uintN flags; /* Fast path for native iterators */ if (OBJ_GET_CLASS(cx, iterobj) == &js_IteratorClass) { flags = JSVAL_TO_INT(OBJ_GET_SLOT(cx, iterobj, JSSLOT_ITER_FLAGS)); if (flags & JSITER_ENUMERATE) return CallEnumeratorNext(cx, iterobj, flags, rval); /* * Call next directly as all the methods of the native iterator are * read-only and permanent. */ if (!IteratorNextImpl(cx, iterobj, rval)) return JS_FALSE; } else { jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); if (!JS_GetMethodById(cx, iterobj, id, &iterobj, rval)) return JS_FALSE; if (!js_InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { /* Check for StopIteration. */ if (!cx->throwing || JSVAL_IS_PRIMITIVE(cx->exception) || OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(cx->exception)) != &js_StopIterationClass) { return JS_FALSE; } /* Inline JS_ClearPendingException(cx). */ cx->throwing = JS_FALSE; cx->exception = JSVAL_VOID; *rval = JSVAL_HOLE; return JS_TRUE; } } return JS_TRUE;}static JSBoolstopiter_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp){ *bp = !JSVAL_IS_PRIMITIVE(v) && OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_StopIterationClass; return JS_TRUE;}JSClass js_StopIterationClass = { js_StopIteration_str, JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, NULL, NULL, NULL, NULL, NULL, stopiter_hasInstance, NULL, NULL};#if JS_HAS_GENERATORSstatic voidgenerator_finalize(JSContext *cx, JSObject *obj){ JSGenerator *gen; gen = (JSGenerator *) JS_GetPrivate(cx, obj); if (gen) { /* * gen can be open on shutdown when close hooks are ignored or when * the embedding cancels scheduled close hooks. */ JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_CLOSED || gen->state == JSGEN_OPEN); JS_free(cx, gen); }}static uint32generator_mark(JSContext *cx, JSObject *obj, void *arg){ JSGenerator *gen; gen = (JSGenerator *) JS_GetPrivate(cx, obj); if (gen) { /* * We must mark argv[-2], as js_MarkStackFrame will not. Note that * js_MarkStackFrame will mark thisp (argv[-1]) and actual arguments, * plus any missing formals and local GC roots. */ JS_ASSERT(!JSVAL_IS_PRIMITIVE(gen->frame.argv[-2])); GC_MARK(cx, JSVAL_TO_GCTHING(gen->frame.argv[-2]), "generator"); js_MarkStackFrame(cx, &gen->frame); } return 0;}JSClass js_GeneratorClass = { js_Generator_str, JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, generator_finalize, NULL, NULL, NULL, NULL, NULL, NULL, generator_mark, NULL};/* * Called from the JSOP_GENERATOR case in the interpreter, with fp referring * to the frame by which the generator function was activated. Create a new * JSGenerator object, which contains its own JSStackFrame that we populate * from *fp. We know that upon return, the JSOP_GENERATOR opcode will return * from the activation in fp, so we can steal away fp->callobj and fp->argsobj * if they are non-null. */JSObject *js_NewGenerator(JSContext *cx, JSStackFrame *fp){ JSObject *obj; uintN argc, nargs, nvars, depth, nslots; JSGenerator *gen; jsval *newsp; /* After the following return, failing control flow must goto bad. */ obj = js_NewObject(cx, &js_GeneratorClass, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -