该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-02-06
孙向晖 sunshineormer at hotmail.com 在正式开始之前,先说点关于RHG的话题,我的JHG系列,基本是在仿照着RHG的风格在写作。RHG的述事风格很有条理性,并且会指导你跳过跳过再跳过一些无关痛痒的程序片段。这是对的,在一大堆程序中,能够快速准确的定位,不是件很容易的事情。 从今天开始,我将讲述我对蜘蛛猴源代码的查找过程: 在js.c 找到main里面的调用过程,注意,下面的函数都是精简过的,而且是平级的关系: rt = JS_NewRuntime(... cx = JS_NewContext(rt,... glob = JS_NewObject(cx, &global_class, NULL, NULL); JS_InitStandardClasses(cx, glob) JS_DefineFunctions(cx, glob, shell_functions) <o:p> </o:p> ok,现在来看一下,运行时和上下文环境是解释引擎的初始化,可以先跳过,哈,我们真正关心的肯定是从glob开始的那3句了:glob是ECMA262中要求的内置全局对象,这里有我们比较感兴趣的NewObject方法;紧接其后的,将是对其他内置对象的创建过程(JS_InitStandardClasses);最后,我们可以看看全局对象global都有哪些方法。 <o:p> </o:p> JS_NewObject的函数声明,被定义在jsobj.h中,函数定义在jsobj.c中: : extern JSObject * js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent); 记住,因为是要初始化glob对象,我们在传递参数是,proto和parent都传递了NULL。这样,有效传递到函数体中的,就只有刚刚创建的上下文环境(cx)和clasp了。clasp的值被赋予了global_class,这是个全局变量,定义在js.c中 <o:p> </o:p> JSClass global_class = { "global", JSCLASS_NEW_RESOLVE | JSCLASS_GLOBAL_FLAGS, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, global_enumerate, (JSResolveOp) global_resolve, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS }; <o:p> </o:p> 在这个变量中,我们发现了“global”这个单词,结合JSClass这名字,再根据MFC等框架的经验,很容易的我们就可以联想到,这是用来做动态生成和RTTI的类名。 要想看懂这个结构体,一点也不难,只需到jsapi.h中找JSClass的定义即可。里面也没有什么太多的玩意,只是有一堆的函数指针,我们只需简单留意其中的强制非空部分即可。 <o:p> </o:p> struct JSClass { const char *name; uint32 flags; <o:p> </o:p> /* Mandatory non-null function pointer members. */ JSPropertyOp addProperty; JSPropertyOp delProperty; JSPropertyOp getProperty; JSPropertyOp setProperty; JSEnumerateOp enumerate; JSResolveOp resolve; JSConvertOp convert; JSFinalizeOp finalize; <o:p> </o:p> /* Optionally non-null members start here. */ JSGetObjectOps getObjectOps; JSCheckAccessOp checkAccess; JSNative call; JSNative construct; JSXDRObjectOp xdrObject; JSHasInstanceOp hasInstance; JSMarkOp mark; JSReserveSlotsOp reserveSlots; }; 放眼望去,偶的老天,原来类的属性操作(增加属性,删除属性,查询和设置属性都是在这定义的啊)。要知道,在javascript中,所有的attributes和方法都是属性啊。按下不表。 还是跳回到newObject <o:p> </o:p> /* Bootstrap the ur-object, and make it the default prototype object. */ if (!proto) { if (!js_GetClassId(cx, clasp, &id)) return NULL; if (!js_GetClassPrototype(cx, parent, id, &proto)) return NULL; if (!proto && !js_GetClassPrototype(cx, parent, INT_TO_JSID(JSProto_Object), &proto)) { return NULL; } } 先看这段代码,简而言之,想做的事情是,找到要创建对象的原型,如果实在找不到,就使用缺省的原型对象。跳过。 接下来的代码, /* Always call the class's getObjectOps hook if it has one. */ ops = clasp->getObjectOps ? clasp->getObjectOps(cx, clasp) : &js_ObjectOps; 只是想找一个对象的操作方法集,因为我们在定义global_class全局对象时,使用了JSCLASS_NO_OPTIONAL_MEMBERS宏,可以很轻松的判定这个表达式如同: ops = &js_ObjectOps; <o:p> </o:p> 继续向后: /* * Allocate a zeroed object from the GC heap. Do this *after* any other * GC-thing allocations under js_GetClassPrototype or clasp->getObjectOps, * to avoid displacing the newborn root for obj. */ obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject)); if (!obj) return NULL; 从注释中,我们可以轻松的看出,按照ECMAScript的说法,对象被分配到heap中,已经得到了实现了。 被定义在了jsgc.c中,我们不想太多的去看堆的alloc分配,只要知道这里生成了一个空的JSObject对象即可。 void * js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) 再接着,是一大段的判断条件,想法很简单,既而是已经在heap中创建了对象,就要给对象的map和slot进行赋值了:一种做法是判断了若干条件后,用原型的map;另一种可能,是创建新的map。 <o:p> </o:p> 你会问map里面都存放了什么?呵呵。好问题。且听下回分解吧。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 1576 次