介绍
SpiderMonkey是Firefox使用的脚本引擎,V8是Google Chrome使用的脚本引擎。这篇文章介绍了怎样在自己的C++程序中嵌入这两种脚本引擎,以及简单做了一些横向的对比。
编译
SpiderMonkey篇
SpiderMonkey支持1.0~1.8版本的JavaScript语法,包括ECMAScript,ECMA 263-3,以及Mozilla扩展,可选支持E4X
由于SpiderMonkey的makefile只支持GNU Make。为了便于编译,建议使用MSYS,请先准备好MSYS(http://www.mingw.org)
下载SpiderMonkey源代码(https://developer.mozilla.org/En/SpiderMonkey/1.8)
解压...
1. 从“VC命令提示”进入控制台,然后进入到MSYS中,这样做的目的是为了让MSYS能使用VC的编译器。
2. 在MSYS里,用cd命令进入到SpiderMonkey源代码目录中
3. 输入make -f makefile.ref BUILD_OPT=1
这样就编译完成了,还算简单吧。
BUILD_OPT=1参数的作用是把SpiderMonkey编译成Release版本。
另外,默认是使用VC的运行库的(即使用-MD编译参数),如果不喜欢,可以修改src\confg目录下的*.mk文件(比如把-MD改成-MT)
对于MinGW用户,请参考这里http://jargon.ca/spidermonkey/编译
V8篇
不知道Google为什么把他们的脚本引擎称为V8,其宣称V8的速度远远超过SpiderMonkey,同样支持支持ECMAScript、ECMA-262-3。
下载V8源代码,需要安装SVN,命令是svn checkout http://v8.googlecode.com/svn/trunk/ v8 或者可以在本站下载(见文章末尾)
下载后解压...
可以在tools\visual_studio里找到工程文件,直接打开工程文件就可以编译了。
如果编译成功,可以无视下面这段。如果没搞定,请静下心来继续...
命令行编译方法
需要Python2.4以上版本(http://www.python.org )
安装scons(http://www.scons.org ),这是一个python的编译脚本软件,可以把它看作是“高级”一点的make。
1. 进入“VC命令提示”
2. 进入V8目录
3. 设置Python路径 set path=c:\Python25;c:\Python25\Scripts;%path%
官方文档说到这一步输入scons就可以开始编译了
不过例外总是有的,比如我的VC2005就不行,一会儿说找不到cl命令,一会儿又找不到头文件-_-
我们得告诉它环境变量的值,这样写就可以了:
scons env="PATH:%path%,INCLUDE:%include%,LIB:%lib%"
默认是静态链接,静态VC库,可以这样修改编译参数
scons library=shared msvcrt=shared env=...
输入scons --help能看到更多编译参数
想在MinGW里编译,要到这里下个补丁才行:http://codereview.chromium.org/18309
注意:如果编译成动态库,使用时包含头文件v8.h之前应该先来一句 #define USING_V8_SHARED 1
对比
偶不打算把这篇文章写成权威的横向评测报告(听见有人说:切~~没这个能力还嘴硬,-_-!!!)。只是简单地比较一下脚本运行速度、脚本与宿主程序之间通信速度以及编程的简易程度。我想这也是C++编程人员关心的主要问题。
先放上比较用的脚本:
脚本运行速度测试脚本
这是一个从网上找来的计算Pi的JS脚本
1. mess="";
2. //10^11 seems to be the maximum
3. //too high a figure for the base introduces errors
4. Base=Math.pow(10,11);
5. //num digits in each array item
6. cellSize=Math.floor(Math.log(Base)/Math.LN10);
7. //below is not used in this script
8. a=Number.MAX_VALUE;
9. MaxDiv=Math.floor(Math.sqrt(a));
10. function makeArray (n, aX, Integer) {
11. var i=0;
12. for (i=1; i<n; i++)
13. aX[i] = null;
14. aX[0] = Integer;
15. }
16. function isEmpty (aX) {
17. var empty=true
18. for (i=0; i<aX.length; i++)
19. if (aX[i])
20. {
21. empty= false;
22. break;
23. }
24. return empty;
25. }
26. //junior school math
27. function Add (n, aX,aY) {
28. carry=0
29. for (i=n-1; i>=0; i--) {
30. aX[i] += Number(aY[i])+Number(carry);
31. if (aX[i]<Base)
32. carry = 0;
33. else {
34. carry = 1;
35. aX[i] =Number(aX[i])- Number(Base);
36. }
37. }
38. }
39. //subtract
40. function Sub (n, aX,aY) {
41. for (i=n-1; i>=0; i--) {
42. aX[i] -= aY[i];
43. if (aX[i]<0) {
44. if (i>0) {
45. aX[i] += Base;
46. aX[i-1]--;
47. }
48. }
49. }
50. }
51. //multiply big number by "small" number
52. function Mul (n, aX, iMult) {
53. carry=0;
54. for (i=n-1; i>=0; i--) {
55. prod = (aX[i])*iMult;
56. prod += carry;
57. if (prod>=Base) {
58. carry = Math.floor(prod/Base);
59. prod -= (carry*Base);
60. }
61. else
62. carry = 0;
63. aX[i] = prod;
64. }
65. }
66. //divide big number by "small" number
67. function Div (n, aX, iDiv,aY) {
68. carry=0;
69. for (i=0; i<n; i++) {
70. //add any previous carry
71. currVal = Number(aX[i])+Number(carry*Base);
72. //divide
73. theDiv =Math.floor(currVal/iDiv);
74. //find next carry
75. carry = currVal-theDiv*iDiv;
76. //put the result of division in the current slot
77. aY[i] = theDiv;
78. }
79. }
80. //compute arctan
81. function arctan (iAng, n, aX) {
82. iAng_squared=iAng*iAng;
83. k=3; //k is the coefficient in the series 2n-1, 3,5..
84. sign=0;
85. makeArray (n, aX, 0); //aX is aArctan
86. makeArray (n, aAngle, 1);
87. Div (n, aAngle, iAng, aAngle); //aAngle = 1/iAng, eg 1/5
88. Add (n, aX, aAngle); // aX = aAngle or long angle
89. while (!isEmpty(aAngle)) {
90. Div (n, aAngle, iAng_squared, aAngle); //aAngle=aAngle/iAng_squared, iAng_squared is iAng*iAng
91. Div (n, aAngle, k, aDivK); /* aDivK = aAngle/k */
92. if (sign)
93. Add (n, aX, aDivK); /* aX = aX+aDivK */
94. else Sub (n, aX, aDivK); /* aX = aX-aDivK */
95. k+=2;
96. sign = 1-sign;
97. }
98. mess+="aArctan="+aArctan+"<br>";
99. }
100. // Calculate pi
101. function calcPI (numDec) {
102. var ans="";
103. t1=new Date();
104. numDec=Number(numDec)+5;
105. iAng=new Array(10);
106. coeff=new Array(10);
107. arrayLength=Math.ceil(1+numDec/cellSize);
108. aPI = new Array(arrayLength);
109. aArctan = new Array(arrayLength);
110. aAngle=new Array(arrayLength);
111. aDivK=new Array(arrayLength);
112. //Pi/4 = 4*arctan(1/5)-arctan(1/239)
113. //coeff is an array of the coefficients
114. //the last item is 0!
115. coeff[0] = 4;
116. coeff[1] = -1;
117. coeff[2] = 0;
118. //iAng holds the angles, 5 for 1/5, etc
119. iAng[0] = 5;
120. iAng[1] = 239;
121. iAng[2] = 0;
122. makeArray (arrayLength, aPI, 0);
123. //Machin: Pi/4 = 4*arctan(1/5)-arctan(1/239)
124. makeArray(arrayLength,aAngle,0);
125. makeArray(arrayLength,aDivK,0);
126. for (var i=0; coeff[i]!=0; i++) {
127. arctan(iAng[i], arrayLength, aArctan);
128. //multiply by coefficients of arctan
129. Mul (arrayLength, aArctan, Math.abs(coeff[i]));
130. if (coeff[i]>0)
131. Add (arrayLength, aPI, aArctan);
132. else
133. Sub (arrayLength, aPI, aArctan);
134. }
135. //we have calculated pi/4, so need to finally multiply
136. Mul (arrayLength, aPI, 4);
137. //we have now calculated PI, and need to format the answer
138. //to print it out
139. sPI="";
140. tempPI="";
141. //put the figures in the array into the string tempPI
142. for (i=0;i<aPI.length;i++)
143. {
144. aPI[i]=String(aPI[i]);
145. //ensure there are enough digits in each cell
146. //if not, pad with leading zeros
147. if (aPI[i].length<cellSize&&i!=0)
148. {
149. while (aPI[i].length<cellSize)
150. aPI[i]="0"+aPI[i];
151. }
152. tempPI+=aPI[i];
153. }
154. //now put the characters into the string sPI
155. for (i=0;i<=numDec;i++)
156. {
157. //put the 3 on a different line, and add a decimal point
158. if (i==0)
159. sPI+=tempPI.charAt(i)+". ";
160. else
161. {
162. if ((i)%50==0&&i!=0)
163. sPI+=tempPI.charAt(i)+" ";
164. else
165. sPI+=tempPI.charAt(i);
166. }//i not zero
167. }
168. //now put the print-out together
169. //print our pi
170. ans+=("PI ("+numDec+")="+sPI+" ");
171. //Window's calculator Pi (for confirmation);
172. ans+=("Win PI= 3.1415926535897932384626433832795 ");
173. t2=new Date();
174. timeTaken=(t2.getTime()-t1.getTime())/1000;
175. ans+="It took: "+timeTaken+" seconds";
176. return ans;
177.
178. }
179.
180. myprint(calcPI(1000));
脚本与宿主程序之间通信速度测试脚本
1. // MyClass是宿主提供给JS的类(一个queue的直接包装)
2. var c = new MyClass();
3. t1=new Date();
4.
5. //10万次push和pop,测试JS调用宿主代码的速度
6. for(i=0; i<100000; i++)
7. {
8. c.push(i);
9. c.pop();
10. }
11. t2=new Date();
12. timeTaken=(t2.getTime()-t1.getTime())/1000;
13. //myprint也是宿主提供的全局函数,用于显示结果
14. myprint("It took:",timeTaken,"seconds");
接下来我们开始编写代码,利用SpiderMonkey和V8引擎分别实现出能够执行上述脚本的程序,看看哪个速度更快吧~~
下载