`
RednaxelaFX
  • 浏览: 3016482 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

KJS的一些简略笔记

阅读更多
今天原本是在cnBeta上看新闻的,看到KDE 4.0.1的发布消息时留意到其中提到Konquerer的JavaScript引擎(KJS)的更新,突然就心痒起来,到KDE的SVN去抓了KJS的代码下来看。粗略浏览了几个文件,做点记录。
KDE的svn trunk地址:svn://anonsvn.kde.org/home/kde/trunk/KDE
其中KJS的部分是:svn://anonsvn.kde.org/home/kde/trunk/KDE/kdelibs/kjs
今天抓到的是revision 772368。话说代码里不是考虑到了MSVC的兼容性了么,为什么没见到MSVC的project/workspace/solution文件的?难道是在KDE的大包里么……回头得再找找。或者回头试试在MinGW里build一下看行不行。

KJS是由Harri Porten为KDE的浏览器Konquerer而编写的JavaScript引擎,目前支持的是ECMAScript 3。在一些实现细节上,KJS似乎更倾向于与IE的JScript的行为相兼容(相比于倾向Mozilla/FF)。未实现E4X。实现了Mozilla扩展的__getter__和__setter__以及相关设施。
Apple的WebKit中的JavaScript引擎JavaScriptCore基于KJS。Safari自然也是使用JavaScriptCore的咯。在JavaScriptCore的介绍页面上的todo-list有点意思。
对了,不要忘记看看John Resig制作的ECMAScript族谱哦:http://ejohn.org/files/ecma-cloud.png

KJS的代码看起来很干净。阅读的时候感觉比较轻松。在我读过的JavaScript引擎的源代码中,KJS可能是第二容易阅读的。第一是Rhino,再怎么说用Java来写代码便是限制住了些恶心的东西(例如我很讨厌的宏……),而且也不用自己写GC了,交给下面的JVM就行。而Rhino的兄长,Mozilla SpiderMonkey则有不少恶心代码;嗯,不过应该说还算好的了。想来我读过的JavaScript-like语言的实现中最恶心的可能还是吉里吉里2里的TJS……以上纯粹个人喜好意义上的评论。

KJS中,解释器前端的lexer是手写的(lexer.h/cpp),没什么特别,就是一个ad hoc的DFA。没有用到正则表达式的库。关键字匹配是委托给Lookup类完成的,其中用到了hash table。lexer.h里有个奇怪的地方,明明声明了int lookupKeyword(const char *);却没有任何地方实现了这个方法,是refactor的时候漏了改么。lexer.cpp, line 578的有这么行注释:
// Hack for "f = function somename() { ... }", too hard to get into the grammar

想起之前在es4-discuss上讨论关于FunDeclInSmt的问题,记个链接:Function declarations in statements。上面那行注释对应的是FunExpr的状况。嗯回头留意下别的JavaScript引擎是怎么处理这个语法的。
Parser则是bison生成的(grammar.y/h/cpp,Parser.h/cpp)。中间是一棵抽象语法树。后端是一个tree-walker形式的解释器(主要在interpreter.h/cpp)。
解释器状态在ExecState中保存(ExecState.h/cpp)。每个解释器实例应使用一个独特的JSObject作为globalObejct。解释器允许在多线程环境下使用,为了保证线程安全,引擎实现了锁(JSLock.h/cpp)。

基本的类型层次从JSValue类开始。
JSValue <- primitive type及Object的实现类的基类。但只有primitive type直接继承自该类
  └JSCell <- 为GC需要而设立的一个基类
     └JSObject <- Object的实现类,也是其它non-primitive type的基类。


GC则是使用mark-and-sweep算法。没有分代。mark用bitmap来记录。GC功能主要在collector.h/cpp中实现。

KJS中注册native function的方式真独特。以前还没见过这么做的,唉唉,孤陋寡闻了。
举个例子,看看KJS中Boolean.prototype的实现部分。
bool_object.h, line 52:
/**
 * @internal
 *
 * Class to implement all methods that are properties of the
 * Boolean.prototype object
 */
class BooleanProtoFunc : public InternalFunctionImp {
public:
  BooleanProtoFunc(ExecState*, FunctionPrototype*, int i, int len, const Identifier&);

  virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);

  enum { ToString, ValueOf };
private:
  int id;
};


bool_object.cpp, line 65:
// ECMA 15.6.4.2 + 15.6.4.3
JSValue *BooleanProtoFunc::callAsFunction(ExecState* exec, JSObject *thisObj, const List &/*args*/)
{
  // no generic function. "this" has to be a Boolean object
  if (!thisObj->inherits(&BooleanInstance::info))
    return throwError(exec, TypeError);

  // execute "toString()" or "valueOf()", respectively

  JSValue *v = static_cast<BooleanInstance*>(thisObj)->internalValue();
  assert(v);

  if (id == ToString)
    return jsString(v->toString(exec));
  return jsBoolean(v->toBoolean(exec)); /* TODO: optimize for bool case */
}


像这样,Boolean.prototype.ToString()和Boolean.prototype.ValueOf()就被实现为一个JSObject::callAsFunction()了,在callAsFunction()里通过id来区别具体要调用的是哪个函数。id所用到的值得范围则是由一个enum提供的。
天啊。在Boolean里还好只有2个方法,但在Math和Date里,原生提供的方法就多多了,Object.prototype也是……结果看到的是这种代码:
math_object.h, line 37:
enum { Euler, Ln2, Ln10, Log2E, Log10E, Pi, Sqrt1_2, Sqrt2,
       Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Pow,
       Exp, Floor, Log, Max, Min, Random, Round, Sin, Sqrt, Tan };


math_object.cpp, line 85:
JSValue *MathObjectImp::getValueProperty(ExecState *, int token) const
{
  double d = -42; // ;)
  switch (token) {
  case Euler:
    d = exp(1.0);
    break;
  case Ln2:
    d = log(2.0);
    break;
  //... other cases omitted
  }
  
  return jsNumber(d);
}


math_object.cpp, line 131:
JSValue *MathFuncImp::callAsFunction(ExecState *exec, JSObject* /*thisObj*/, const List &args)
{
  double arg = args[0]->toNumber(exec);
  double arg2 = args[1]->toNumber(exec);
  double result;

  switch (id) {
  case MathObjectImp::Abs:
    result = ( arg < 0 || arg == -0) ? (-arg) : arg;
    break;
  case MathObjectImp::ACos:
    result = ::acos(arg);
    break;
  case MathObjectImp::ASin:
    result = ::asin(arg);
    break;
  //... other cases omitted
  }
  
  return jsNumber(result);
}


这里可是26个方法给switch(id)了……

KDE提供了一个方便将KJS嵌入别的KDE/Qt应用的库KJSEmbed。不知道KJSEmbed里是怎么将native function绑定到JavaScript端的,不过想来跟KJS的做法应该一样(因为被KJS的JSObject固定了)?

(更新:顺便就把KJSEmbed也抓了下来。svn trunk: svn://anonsvn.kde.org/home/kde/trunk/KDE/kdelibs/kjsembed
其中qobject_binding.h(197)/qobject_binding.cpp(604),static_binding.h(49,93)/static_binding.cpp(41)确实也出现了callAsFunction()。不过却没有前述的enum+switch(id);SlotBinding类里有个switch(returnTypeId),不过跟前面的那种switch比较不一样了。
取而代之,恶心的宏出现了 T T
qobject_binding.h, line 38:
/**
* A simple pointer syle method.
* This will extract the pointer, cast it to the native type and place it in "value".
* Any data that should be returned from this method should be placed into "result";
*
*/
#define START_QOBJECT_METHOD( METHODNAME, TYPE) \
KJS::JSValue *METHODNAME( KJS::ExecState *exec, KJS::JSObject *self, const KJS::List &args ) \
{ \
        Q_UNUSED( args ); \
        KJS::JSValue *result = KJS::jsNull(); \
        KJSEmbed::QObjectBinding *imp = KJSEmbed::extractBindingImp<KJSEmbed::QObjectBinding>(exec, self ); \
        if( imp ) \
        { \
            TYPE *object = imp->qobject<TYPE>(); \
            if( object ) \
            {

/**
* End a variant method started by START_QOBJECT_METHOD
*/
#define END_QOBJECT_METHOD \
            } \
            else \
                KJS::throwError(exec, KJS::ReferenceError, QString("QO: The internal object died %1:%2.").arg(__FILE__).arg(__LINE__));\
        } \
        else \
           KJS::throwError(exec, KJS::ReferenceError, QString("QObject died."));\
        return result; \
}

这这这……我讨厌这样的宏 T T
但我也确实没见过什么别的好办法。总不能每次都重复的手写那些代码吧。


以后想起来了再慢慢更新……

P.S. 祝大家新年快乐噢~
3
0
分享到:
评论
1 楼 lwwin 2008-02-09  
看代码还真不如看你的解释来的痛快,偶貌似没啥耐心……
新年也快乐^^

相关推荐

    KJS101控制设备在综采工作面的应用

    本文介绍了年产能力千万吨矿的综采工作面的KTC101集中控制系统、KE3004组合开关的功能,阐述了在KTC101集中控制系统和KE3004组合开关中增加了KJS101输入、输出控制设备,从而将工作面转载机的电机即时工作电流采集到...

    KJS-10使用说明书(单机标准版).pdf

    科捷地磅说明书

    EPPC-1282kjs说明书.zip

    EPPC-1282kjs说明书zip,EPPC-1282kjs说明书

    chrome-kjs-crx插件

    语言:English,中文 (简体) Web开发辅助插件,集成二维码、常见的加密方法... Web开发辅助插件,集成地址栏url生成二维码,鼠标右键菜单增加自定义搜索引擎搜索选中文字

    派特莱KJS 系列多层小型方形旋转报警灯2D CAD.dxf

    派特莱KJS 系列多层小型方形旋转报警灯2D CADdxf,特点:发挥旋转报警灯的散光优势,提高报警可视范围,自然提升视觉反应。体积小节省平面空间,带内置蜂鸣器,是大型机器,重工机械的最佳选择。科学的抛物线反射镜,...

    JAVA1111111111111111

    学习JAVA基础1111111111111122121122

    java8看不到源码-javascript-semantics:KJS:JavaScript的完整形式语义

    看不到源码KJS:JavaScript 的完整形式语义 KJS 是迄今为止最完整且经过彻底测试的 JavaScript 形式语义。 作为可执行文件,KJS 已针对 进行了测试,并通过了所有 2,782 项核心语言测试。 除了 JavaScript 的参考...

    铬KJS「chrome-kjs」-crx插件

    Web开发辅助插件,集成二维码、常见的加密方法... Web开发辅助插件,集成地址栏url生成二维码,鼠标右键菜单增加自定义搜索引擎搜索选中文字 支持语言:English,中文 (简体)

    tijscore:Titanium Mobile基于KJS的前叉

    这是WebKit KJS的Titanium Mobile分支。 所有更改都可以在Apache Public License(版本2)下获得。 要构建,首先运行WTF脚本,然后运行TiCore脚本。 生成的库以及来自WTF和JavaScriptCore项目(调试器/探查器/钛...

    kjs3870.github.io

    扢 语言:英语| 一个最小的,侧边栏,响应式Web设计Jekyll主题,专注于文本演示。 旨在帮助您轻松记录和共享知识。 目录 特征 已标记的帖子 可配置主题模式 双层类别 帖子的上次修改日期 ... 从RubyGems安装-易于更新...

    如何打造仅1k大小的纯JS脚本3D玫瑰

    如何打造仅1k大小的纯JS脚本3D玫瑰 源码,可直接运行

    adminportal.rar

    本代码为(辞林)书店后台管理系统,,课设代码,水平有限,有不对的地方望谅解

    计算器源程序--c#写的源代码

    kjs = int.Parse(sz[i]) * int.Parse(sz[i + 1]); ths = sz[i] + "*" + sz[i + 1]; kh = kh.Replace(ths, kjs.ToString()); } if (fh[i] == '/') { kjs = int.Parse(sz[i]) / int.Parse(sz[i + 1]); ths = ...

    iOS一键添加html数据

    WebKit是一个开源项目,主要由KDE的KHTML修改而来并且包含了一些来自苹果公司的一些组件。 传统上,WebKit包含一个网页引擎WebCore和一个脚本引擎JavaScriptCore,它们分别对应的是KDE的KHTML和KJS。不过, 随着...

    WebKit研究报告

    同时WebKit 也是苹果Mac OS X 系统引擎框架版本的名称,主要用于Safari,Dashboard,Mail 和其他一些Mac OS X 程序。WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎来自于 KDE 的 KHTML 和 KJS,当年苹果比较了 ...

    webkit分析报告2

    同时WebKit 也是苹果Mac OS X 系统引擎框架版本的名称,主要用于Safari,Dashboard,Mail 和其他一些Mac OS X 程序。WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎来自于 KDE 的 KHTML 和 KJS,当年苹果比较了 ...

    GBK.js实现中文编码

    用于js中实现GBK编码。适合使用js进行页面参数传递时,给GBK编码页面传递参数,解决乱码问题。使用时直接引入,然后decode即可,示例如下: const GBK = require("gbk.js"); GBK.decode(data);

    工资管理系统

    登录的用户和密码均为KJS

    Webkit r37113 For Windows

    同时WebKit 也是苹果Mac OS X 系统引擎框架版本的名称,主要用于Safari,Dashboard,Mail 和其他一些Mac OS X 程序。WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎来自于 KDE 的 KHTML 和 KJS,当年苹果比较了 ...

    WebKit.Interop_浏览器源码_webkit_

    同时WebKit 也是苹果Mac OS X 系统引擎框架版本的名称,主要用于Safari,Dashboard,Mail 和其他一些Mac OS X 程序。WebKit 前身是 KDE 小组的 KHTML,WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎来自于 KDE 的...

Global site tag (gtag.js) - Google Analytics