📄 jsparse.c
字号:
js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun){ JSArenaPool codePool, notePool; JSCodeGenerator funcg; JSStackFrame *fp, frame; JSObject *funobj; JSParseNode *pn; JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode)); JS_InitArenaPool(¬ePool, "note", 1024, sizeof(jssrcnote)); if (!js_InitCodeGenerator(cx, &funcg, &codePool, ¬ePool, ts->filename, ts->lineno, ts->principals)) { return JS_FALSE; } /* Prevent GC activation while compiling. */ JS_KEEP_ATOMS(cx->runtime); /* Push a JSStackFrame for use by FunctionBody. */ fp = cx->fp; funobj = fun->object; JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj && fp->scopeChain != funobj)); memset(&frame, 0, sizeof frame); frame.fun = fun; frame.varobj = frame.scopeChain = funobj; frame.down = fp; frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO : JSFRAME_COMPILING; cx->fp = &frame; /* * Farble the body so that it looks like a block statement to js_EmitTree, * which is called beneath FunctionBody; see Statements, further below in * this file. FunctionBody pushes a STMT_BLOCK record around its call to * Statements, so Statements will not compile each statement as it loops * to save JSParseNode space -- it will not compile at all, only build a * JSParseNode tree. * * Therefore we must fold constants, allocate try notes, and generate code * for this function, including a stop opcode at the end. */ CURRENT_TOKEN(ts).type = TOK_LC; pn = FunctionBody(cx, ts, fun, &funcg.treeContext); if (pn && !js_NewScriptFromCG(cx, &funcg, fun)) pn = NULL; /* Restore saved state and release code generation arenas. */ cx->fp = fp; JS_UNKEEP_ATOMS(cx->runtime); js_FinishCodeGenerator(cx, &funcg); JS_FinishArenaPool(&codePool); JS_FinishArenaPool(¬ePool); return pn != NULL;}/* * Parameter block types for the several Binder functions. We use a common * helper function signature in order to share code among destructuring and * simple variable declaration parsers. In the destructuring case, the binder * function is called indirectly from the variable declaration parser by way * of CheckDestructuring and its friends. */typedef struct BindData BindData;typedef JSBool(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc);struct BindData { JSParseNode *pn; /* error source coordinate */ JSTokenStream *ts; /* fallback if pn is null */ JSObject *obj; /* the variable object */ JSOp op; /* prolog bytecode or nop */ Binder binder; /* binder, discriminates u */ union { struct { JSFunction *fun; /* must come first! see next */ } arg; struct { JSFunction *fun; /* this overlays u.arg.fun */ JSClass *clasp; JSPropertyOp getter; JSPropertyOp setter; uintN attrs; } var; struct { jsuint index; uintN overflow; } let; } u;};/* * Given BindData *data and JSREPORT_* flags, expand to the second and third * actual parameters to js_ReportCompileErrorNumber. Prefer reporting via pn * to reporting via ts, for better destructuring error pointers. */#define BIND_DATA_REPORT_ARGS(data, flags) \ (data)->pn ? (void *)(data)->pn : (void *)(data)->ts, \ ((data)->pn ? JSREPORT_PN : JSREPORT_TS) | (flags)static JSBoolBumpFormalCount(JSContext *cx, JSFunction *fun){ if (fun->nargs == JS_BITMASK(16)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_ARGS); return JS_FALSE; } fun->nargs++; return JS_TRUE;}static JSBoolBindArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc){ JSObject *obj, *pobj; JSProperty *prop; JSBool ok; uintN dupflag; JSFunction *fun; const char *name; obj = data->obj; ok = js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop); if (!ok) return JS_FALSE; dupflag = 0; if (prop) { JS_ASSERT(pobj == obj); name = js_AtomToPrintableString(cx, atom); /* * A duplicate parameter name, a "feature" required by ECMA-262. * We force a duplicate node on the SCOPE_LAST_PROP(scope) list * with the same id, distinguished by the SPROP_IS_DUPLICATE flag, * and not mapped by an entry in scope. */ ok = name && js_ReportCompileErrorNumber(cx, BIND_DATA_REPORT_ARGS(data, JSREPORT_WARNING | JSREPORT_STRICT), JSMSG_DUPLICATE_FORMAL, name); OBJ_DROP_PROPERTY(cx, pobj, prop); if (!ok) return JS_FALSE; dupflag = SPROP_IS_DUPLICATE; } fun = data->u.arg.fun; if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom), js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, dupflag | SPROP_HAS_SHORTID, fun->nargs)) { return JS_FALSE; } return BumpFormalCount(cx, fun);}static JSBoolBindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom){ JSFunction *fun; /* * Can't increase fun->nvars in an active frame, so insist that getter is * js_GetLocalVariable, not js_GetCallVariable or anything else. */ if (data->u.var.getter != js_GetLocalVariable) return JS_TRUE; /* * Don't bind a variable with the hidden name 'arguments', per ECMA-262. * Instead 'var arguments' always restates the predefined property of the * activation objects with unhidden name 'arguments'. Assignment to such * a variable must be handled specially. */ if (atom == cx->runtime->atomState.argumentsAtom) return JS_TRUE; fun = data->u.var.fun; if (!js_AddHiddenProperty(cx, data->obj, ATOM_TO_JSID(atom), data->u.var.getter, data->u.var.setter, SPROP_INVALID_SLOT, data->u.var.attrs | JSPROP_SHARED, SPROP_HAS_SHORTID, fun->u.i.nvars)) { return JS_FALSE; } if (fun->u.i.nvars == JS_BITMASK(16)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_VARS); return JS_FALSE; } fun->u.i.nvars++; return JS_TRUE;}#if JS_HAS_DESTRUCTURING/* * Forward declaration to maintain top-down presentation. */static JSParseNode *DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc, JSTokenType tt);static JSBoolBindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc){ JSAtomListElement *ale; JSFunction *fun; JSObject *obj, *pobj; JSProperty *prop; const char *name; ATOM_LIST_SEARCH(ale, &tc->decls, atom); if (!ale) { ale = js_IndexAtom(cx, atom, &tc->decls); if (!ale) return JS_FALSE; ALE_SET_JSOP(ale, data->op); } fun = data->u.var.fun; obj = data->obj; if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop)) return JS_FALSE; if (prop) { JS_ASSERT(pobj == obj && OBJ_IS_NATIVE(pobj)); name = js_AtomToPrintableString(cx, atom); if (!name || !js_ReportCompileErrorNumber(cx, BIND_DATA_REPORT_ARGS(data, JSREPORT_WARNING | JSREPORT_STRICT), JSMSG_DUPLICATE_FORMAL, name)) { return JS_FALSE; } OBJ_DROP_PROPERTY(cx, pobj, prop); } else { if (!BindLocalVariable(cx, data, atom)) return JS_FALSE; } return JS_TRUE;}#endif /* JS_HAS_DESTRUCTURING */static JSParseNode *FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool lambda){ JSOp op, prevop; JSParseNode *pn, *body, *result; JSTokenType tt; JSAtom *funAtom, *objAtom; JSStackFrame *fp; JSObject *varobj, *pobj; JSAtomListElement *ale; JSProperty *prop; JSFunction *fun; JSTreeContext funtc;#if JS_HAS_DESTRUCTURING JSParseNode *item, *list = NULL;#endif /* Make a TOK_FUNCTION node. */#if JS_HAS_GETTER_SETTER op = CURRENT_TOKEN(ts).t_op;#endif pn = NewParseNode(cx, ts, PN_FUNC, tc); if (!pn) return NULL; /* Scan the optional function name into funAtom. */ ts->flags |= TSF_KEYWORD_IS_NAME; tt = js_GetToken(cx, ts); ts->flags &= ~TSF_KEYWORD_IS_NAME; if (tt == TOK_NAME) { funAtom = CURRENT_TOKEN(ts).t_atom; } else { funAtom = NULL; js_UngetToken(ts); } /* Find the nearest variable-declaring scope and use it as our parent. */ fp = cx->fp; varobj = fp->varobj; /* * Record names for function statements in tc->decls so we know when to * avoid optimizing variable references that might name a function. */ if (!lambda && funAtom) { ATOM_LIST_SEARCH(ale, &tc->decls, funAtom); if (ale) { prevop = ALE_JSOP(ale); if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) { const char *name = js_AtomToPrintableString(cx, funAtom); if (!name || !js_ReportCompileErrorNumber(cx, ts, (prevop != JSOP_DEFCONST) ? JSREPORT_TS | JSREPORT_WARNING | JSREPORT_STRICT : JSREPORT_TS | JSREPORT_ERROR, JSMSG_REDECLARED_VAR, (prevop == JSOP_DEFFUN || prevop == JSOP_CLOSURE) ? js_function_str : (prevop == JSOP_DEFCONST) ? js_const_str : js_var_str, name)) { return NULL; } } if (!AT_TOP_LEVEL(tc) && prevop == JSOP_DEFVAR) tc->flags |= TCF_FUN_CLOSURE_VS_VAR; } else { ale = js_IndexAtom(cx, funAtom, &tc->decls); if (!ale) return NULL; } ALE_SET_JSOP(ale, AT_TOP_LEVEL(tc) ? JSOP_DEFFUN : JSOP_CLOSURE); /* * A function nested at top level inside another's body needs only a * local variable to bind its name to its value, and not an activation * object property (it might also need the activation property, if the * outer function contains with statements, e.g., but the stack slot * wins when jsemit.c's BindNameToSlot can optimize a JSOP_NAME into a * JSOP_GETVAR bytecode). */ if (AT_TOP_LEVEL(tc) && (tc->flags & TCF_IN_FUNCTION)) { JSScopeProperty *sprop; /* * Define a property on the outer function so that BindNameToSlot * can properly optimize accesses. */ JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass); JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj)); if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom), &pobj, &prop)) { return NULL; } if (prop) OBJ_DROP_PROPERTY(cx, pobj, prop); sprop = NULL; if (!prop || pobj != varobj || (sprop = (JSScopeProperty *)prop, sprop->getter != js_GetLocalVariable)) { uintN sflags; /* * Use SPROP_IS_DUPLICATE if there is a formal argument of the * same name, so the decompiler can find the parameter name. */ sflags = (sprop && sprop->getter == js_GetArgument) ? SPROP_IS_DUPLICATE | SPROP_HAS_SHORTID : SPROP_HAS_SHORTID; if (!js_AddHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom), js_GetLocalVariable, js_SetLocalVariable, SPROP_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, sflags, fp->fun->u.i.nvars)) { return NULL; } if (fp->fun->u.i.nvars == JS_BITMASK(16)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_VARS); return NULL; } fp->fun->u.i.nvars++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -