jsrun.c 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063
  1. #include "jsi.h"
  2. #include "utf.h"
  3. #include <assert.h>
  4. static void jsR_run(js_State *J, js_Function *F);
  5. /* Push values on stack */
  6. #define STACK (J->stack)
  7. #define TOP (J->top)
  8. #define BOT (J->bot)
  9. static void js_trystackoverflow(js_State *J)
  10. {
  11. STACK[TOP].t.type = JS_TLITSTR;
  12. STACK[TOP].u.litstr = "exception stack overflow";
  13. ++TOP;
  14. js_throw(J);
  15. }
  16. static void js_stackoverflow(js_State *J)
  17. {
  18. STACK[TOP].t.type = JS_TLITSTR;
  19. STACK[TOP].u.litstr = "stack overflow";
  20. ++TOP;
  21. js_throw(J);
  22. }
  23. static void js_outofmemory(js_State *J)
  24. {
  25. STACK[TOP].t.type = JS_TLITSTR;
  26. STACK[TOP].u.litstr = "out of memory";
  27. ++TOP;
  28. js_throw(J);
  29. }
  30. void *js_malloc(js_State *J, int size)
  31. {
  32. void *ptr = J->alloc(J->actx, NULL, size);
  33. if (!ptr)
  34. js_outofmemory(J);
  35. return ptr;
  36. }
  37. void *js_realloc(js_State *J, void *ptr, int size)
  38. {
  39. ptr = J->alloc(J->actx, ptr, size);
  40. if (!ptr)
  41. js_outofmemory(J);
  42. return ptr;
  43. }
  44. char *js_strdup(js_State *J, const char *s)
  45. {
  46. int n = strlen(s) + 1;
  47. char *p = js_malloc(J, n);
  48. memcpy(p, s, n);
  49. return p;
  50. }
  51. void js_free(js_State *J, void *ptr)
  52. {
  53. J->alloc(J->actx, ptr, 0);
  54. }
  55. js_String *jsV_newmemstring(js_State *J, const char *s, int n)
  56. {
  57. js_String *v = js_malloc(J, soffsetof(js_String, p) + n + 1);
  58. memcpy(v->p, s, n);
  59. v->p[n] = 0;
  60. v->gcmark = 0;
  61. v->gcnext = J->gcstr;
  62. J->gcstr = v;
  63. ++J->gccounter;
  64. return v;
  65. }
  66. #define CHECKSTACK(n) if (TOP + n >= JS_STACKSIZE) js_stackoverflow(J)
  67. void js_pushvalue(js_State *J, js_Value v)
  68. {
  69. CHECKSTACK(1);
  70. STACK[TOP] = v;
  71. ++TOP;
  72. }
  73. void js_pushundefined(js_State *J)
  74. {
  75. CHECKSTACK(1);
  76. STACK[TOP].t.type = JS_TUNDEFINED;
  77. ++TOP;
  78. }
  79. void js_pushnull(js_State *J)
  80. {
  81. CHECKSTACK(1);
  82. STACK[TOP].t.type = JS_TNULL;
  83. ++TOP;
  84. }
  85. void js_pushboolean(js_State *J, int v)
  86. {
  87. CHECKSTACK(1);
  88. STACK[TOP].t.type = JS_TBOOLEAN;
  89. STACK[TOP].u.boolean = !!v;
  90. ++TOP;
  91. }
  92. void js_pushnumber(js_State *J, double v)
  93. {
  94. CHECKSTACK(1);
  95. STACK[TOP].t.type = JS_TNUMBER;
  96. STACK[TOP].u.number = v;
  97. ++TOP;
  98. }
  99. void js_pushstring(js_State *J, const char *v)
  100. {
  101. size_t n = strlen(v);
  102. if (n > JS_STRLIMIT)
  103. js_rangeerror(J, "invalid string length");
  104. CHECKSTACK(1);
  105. if (n <= soffsetof(js_Value, t.type)) {
  106. char *s = STACK[TOP].u.shrstr;
  107. while (n--) *s++ = *v++;
  108. *s = 0;
  109. STACK[TOP].t.type = JS_TSHRSTR;
  110. } else {
  111. STACK[TOP].t.type = JS_TMEMSTR;
  112. STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
  113. }
  114. ++TOP;
  115. }
  116. void js_pushlstring(js_State *J, const char *v, int n)
  117. {
  118. if (n > JS_STRLIMIT)
  119. js_rangeerror(J, "invalid string length");
  120. CHECKSTACK(1);
  121. if (n <= soffsetof(js_Value, t.type)) {
  122. char *s = STACK[TOP].u.shrstr;
  123. while (n--) *s++ = *v++;
  124. *s = 0;
  125. STACK[TOP].t.type = JS_TSHRSTR;
  126. } else {
  127. STACK[TOP].t.type = JS_TMEMSTR;
  128. STACK[TOP].u.memstr = jsV_newmemstring(J, v, n);
  129. }
  130. ++TOP;
  131. }
  132. void js_pushliteral(js_State *J, const char *v)
  133. {
  134. CHECKSTACK(1);
  135. STACK[TOP].t.type = JS_TLITSTR;
  136. STACK[TOP].u.litstr = v;
  137. ++TOP;
  138. }
  139. void js_pushobject(js_State *J, js_Object *v)
  140. {
  141. CHECKSTACK(1);
  142. STACK[TOP].t.type = JS_TOBJECT;
  143. STACK[TOP].u.object = v;
  144. ++TOP;
  145. }
  146. void js_pushglobal(js_State *J)
  147. {
  148. js_pushobject(J, J->G);
  149. }
  150. void js_currentfunction(js_State *J)
  151. {
  152. CHECKSTACK(1);
  153. if (BOT > 0)
  154. STACK[TOP] = STACK[BOT-1];
  155. else
  156. STACK[TOP].t.type = JS_TUNDEFINED;
  157. ++TOP;
  158. }
  159. void *js_currentfunctiondata(js_State *J)
  160. {
  161. if (BOT > 0)
  162. return STACK[BOT-1].u.object->u.c.data;
  163. return NULL;
  164. }
  165. /* Read values from stack */
  166. static js_Value *stackidx(js_State *J, int idx)
  167. {
  168. static js_Value undefined = { { {0}, JS_TUNDEFINED } };
  169. idx = idx < 0 ? TOP + idx : BOT + idx;
  170. if (idx < 0 || idx >= TOP)
  171. return &undefined;
  172. return STACK + idx;
  173. }
  174. js_Value *js_tovalue(js_State *J, int idx)
  175. {
  176. return stackidx(J, idx);
  177. }
  178. int js_isdefined(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TUNDEFINED; }
  179. int js_isundefined(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TUNDEFINED; }
  180. int js_isnull(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNULL; }
  181. int js_isboolean(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TBOOLEAN; }
  182. int js_isnumber(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TNUMBER; }
  183. int js_isstring(js_State *J, int idx) { enum js_Type t = stackidx(J, idx)->t.type; return t == JS_TSHRSTR || t == JS_TLITSTR || t == JS_TMEMSTR; }
  184. int js_isprimitive(js_State *J, int idx) { return stackidx(J, idx)->t.type != JS_TOBJECT; }
  185. int js_isobject(js_State *J, int idx) { return stackidx(J, idx)->t.type == JS_TOBJECT; }
  186. int js_iscoercible(js_State *J, int idx) { js_Value *v = stackidx(J, idx); return v->t.type != JS_TUNDEFINED && v->t.type != JS_TNULL; }
  187. int js_iscallable(js_State *J, int idx)
  188. {
  189. js_Value *v = stackidx(J, idx);
  190. if (v->t.type == JS_TOBJECT)
  191. return v->u.object->type == JS_CFUNCTION ||
  192. v->u.object->type == JS_CSCRIPT ||
  193. v->u.object->type == JS_CCFUNCTION;
  194. return 0;
  195. }
  196. int js_isarray(js_State *J, int idx)
  197. {
  198. js_Value *v = stackidx(J, idx);
  199. return v->t.type == JS_TOBJECT && v->u.object->type == JS_CARRAY;
  200. }
  201. int js_isregexp(js_State *J, int idx)
  202. {
  203. js_Value *v = stackidx(J, idx);
  204. return v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP;
  205. }
  206. int js_isuserdata(js_State *J, int idx, const char *tag)
  207. {
  208. js_Value *v = stackidx(J, idx);
  209. if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
  210. return !strcmp(tag, v->u.object->u.user.tag);
  211. return 0;
  212. }
  213. int js_iserror(js_State *J, int idx)
  214. {
  215. js_Value *v = stackidx(J, idx);
  216. return v->t.type == JS_TOBJECT && v->u.object->type == JS_CERROR;
  217. }
  218. const char *js_typeof(js_State *J, int idx)
  219. {
  220. js_Value *v = stackidx(J, idx);
  221. switch (v->t.type) {
  222. default:
  223. case JS_TSHRSTR: return "string";
  224. case JS_TUNDEFINED: return "undefined";
  225. case JS_TNULL: return "object";
  226. case JS_TBOOLEAN: return "boolean";
  227. case JS_TNUMBER: return "number";
  228. case JS_TLITSTR: return "string";
  229. case JS_TMEMSTR: return "string";
  230. case JS_TOBJECT:
  231. if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
  232. return "function";
  233. return "object";
  234. }
  235. }
  236. int js_type(js_State *J, int idx)
  237. {
  238. js_Value *v = stackidx(J, idx);
  239. switch (v->t.type) {
  240. default:
  241. case JS_TSHRSTR: return JS_ISSTRING;
  242. case JS_TUNDEFINED: return JS_ISUNDEFINED;
  243. case JS_TNULL: return JS_ISNULL;
  244. case JS_TBOOLEAN: return JS_ISBOOLEAN;
  245. case JS_TNUMBER: return JS_ISNUMBER;
  246. case JS_TLITSTR: return JS_ISSTRING;
  247. case JS_TMEMSTR: return JS_ISSTRING;
  248. case JS_TOBJECT:
  249. if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
  250. return JS_ISFUNCTION;
  251. return JS_ISOBJECT;
  252. }
  253. }
  254. int js_toboolean(js_State *J, int idx)
  255. {
  256. return jsV_toboolean(J, stackidx(J, idx));
  257. }
  258. double js_tonumber(js_State *J, int idx)
  259. {
  260. return jsV_tonumber(J, stackidx(J, idx));
  261. }
  262. int js_tointeger(js_State *J, int idx)
  263. {
  264. return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx)));
  265. }
  266. int js_toint32(js_State *J, int idx)
  267. {
  268. return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx)));
  269. }
  270. unsigned int js_touint32(js_State *J, int idx)
  271. {
  272. return jsV_numbertouint32(jsV_tonumber(J, stackidx(J, idx)));
  273. }
  274. short js_toint16(js_State *J, int idx)
  275. {
  276. return jsV_numbertoint16(jsV_tonumber(J, stackidx(J, idx)));
  277. }
  278. unsigned short js_touint16(js_State *J, int idx)
  279. {
  280. return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx)));
  281. }
  282. const char *js_tostring(js_State *J, int idx)
  283. {
  284. return jsV_tostring(J, stackidx(J, idx));
  285. }
  286. js_Object *js_toobject(js_State *J, int idx)
  287. {
  288. return jsV_toobject(J, stackidx(J, idx));
  289. }
  290. void js_toprimitive(js_State *J, int idx, int hint)
  291. {
  292. jsV_toprimitive(J, stackidx(J, idx), hint);
  293. }
  294. js_Regexp *js_toregexp(js_State *J, int idx)
  295. {
  296. js_Value *v = stackidx(J, idx);
  297. if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CREGEXP)
  298. return &v->u.object->u.r;
  299. js_typeerror(J, "not a regexp");
  300. }
  301. void *js_touserdata(js_State *J, int idx, const char *tag)
  302. {
  303. js_Value *v = stackidx(J, idx);
  304. if (v->t.type == JS_TOBJECT && v->u.object->type == JS_CUSERDATA)
  305. if (!strcmp(tag, v->u.object->u.user.tag))
  306. return v->u.object->u.user.data;
  307. js_typeerror(J, "not a %s", tag);
  308. }
  309. static js_Object *jsR_tofunction(js_State *J, int idx)
  310. {
  311. js_Value *v = stackidx(J, idx);
  312. if (v->t.type == JS_TUNDEFINED || v->t.type == JS_TNULL)
  313. return NULL;
  314. if (v->t.type == JS_TOBJECT)
  315. if (v->u.object->type == JS_CFUNCTION || v->u.object->type == JS_CCFUNCTION)
  316. return v->u.object;
  317. js_typeerror(J, "not a function");
  318. }
  319. /* Stack manipulation */
  320. int js_gettop(js_State *J)
  321. {
  322. return TOP - BOT;
  323. }
  324. void js_pop(js_State *J, int n)
  325. {
  326. TOP -= n;
  327. if (TOP < BOT) {
  328. TOP = BOT;
  329. js_error(J, "stack underflow!");
  330. }
  331. }
  332. void js_remove(js_State *J, int idx)
  333. {
  334. idx = idx < 0 ? TOP + idx : BOT + idx;
  335. if (idx < BOT || idx >= TOP)
  336. js_error(J, "stack error!");
  337. for (;idx < TOP - 1; ++idx)
  338. STACK[idx] = STACK[idx+1];
  339. --TOP;
  340. }
  341. void js_insert(js_State *J, int idx)
  342. {
  343. js_error(J, "not implemented yet");
  344. }
  345. void js_replace(js_State* J, int idx)
  346. {
  347. idx = idx < 0 ? TOP + idx : BOT + idx;
  348. if (idx < BOT || idx >= TOP)
  349. js_error(J, "stack error!");
  350. STACK[idx] = STACK[--TOP];
  351. }
  352. void js_copy(js_State *J, int idx)
  353. {
  354. CHECKSTACK(1);
  355. STACK[TOP] = *stackidx(J, idx);
  356. ++TOP;
  357. }
  358. void js_dup(js_State *J)
  359. {
  360. CHECKSTACK(1);
  361. STACK[TOP] = STACK[TOP-1];
  362. ++TOP;
  363. }
  364. void js_dup2(js_State *J)
  365. {
  366. CHECKSTACK(2);
  367. STACK[TOP] = STACK[TOP-2];
  368. STACK[TOP+1] = STACK[TOP-1];
  369. TOP += 2;
  370. }
  371. void js_rot2(js_State *J)
  372. {
  373. /* A B -> B A */
  374. js_Value tmp = STACK[TOP-1]; /* A B (B) */
  375. STACK[TOP-1] = STACK[TOP-2]; /* A A */
  376. STACK[TOP-2] = tmp; /* B A */
  377. }
  378. void js_rot3(js_State *J)
  379. {
  380. /* A B C -> C A B */
  381. js_Value tmp = STACK[TOP-1]; /* A B C (C) */
  382. STACK[TOP-1] = STACK[TOP-2]; /* A B B */
  383. STACK[TOP-2] = STACK[TOP-3]; /* A A B */
  384. STACK[TOP-3] = tmp; /* C A B */
  385. }
  386. void js_rot4(js_State *J)
  387. {
  388. /* A B C D -> D A B C */
  389. js_Value tmp = STACK[TOP-1]; /* A B C D (D) */
  390. STACK[TOP-1] = STACK[TOP-2]; /* A B C C */
  391. STACK[TOP-2] = STACK[TOP-3]; /* A B B C */
  392. STACK[TOP-3] = STACK[TOP-4]; /* A A B C */
  393. STACK[TOP-4] = tmp; /* D A B C */
  394. }
  395. void js_rot2pop1(js_State *J)
  396. {
  397. /* A B -> B */
  398. STACK[TOP-2] = STACK[TOP-1];
  399. --TOP;
  400. }
  401. void js_rot3pop2(js_State *J)
  402. {
  403. /* A B C -> C */
  404. STACK[TOP-3] = STACK[TOP-1];
  405. TOP -= 2;
  406. }
  407. void js_rot(js_State *J, int n)
  408. {
  409. int i;
  410. js_Value tmp = STACK[TOP-1];
  411. for (i = 1; i < n; ++i)
  412. STACK[TOP-i] = STACK[TOP-i-1];
  413. STACK[TOP-i] = tmp;
  414. }
  415. /* Property access that takes care of attributes and getters/setters */
  416. int js_isarrayindex(js_State *J, const char *p, int *idx)
  417. {
  418. int n = 0;
  419. /* check for empty string */
  420. if (p[0] == 0)
  421. return 0;
  422. /* check for '0' and integers with leading zero */
  423. if (p[0] == '0')
  424. return (p[1] == 0) ? *idx = 0, 1 : 0;
  425. while (*p) {
  426. int c = *p++;
  427. if (c >= '0' && c <= '9') {
  428. if (n >= INT_MAX / 10)
  429. return 0;
  430. n = n * 10 + (c - '0');
  431. } else {
  432. return 0;
  433. }
  434. }
  435. return *idx = n, 1;
  436. }
  437. static void js_pushrune(js_State *J, Rune rune)
  438. {
  439. char buf[UTFmax + 1];
  440. if (rune >= 0) {
  441. buf[runetochar(buf, &rune)] = 0;
  442. js_pushstring(J, buf);
  443. } else {
  444. js_pushundefined(J);
  445. }
  446. }
  447. void jsR_unflattenarray(js_State *J, js_Object *obj) {
  448. if (obj->type == JS_CARRAY && obj->u.a.simple) {
  449. js_Property *ref;
  450. int i;
  451. char name[32];
  452. if (js_try(J)) {
  453. obj->properties = NULL;
  454. js_throw(J);
  455. }
  456. for (i = 0; i < obj->u.a.flat_length; ++i) {
  457. js_itoa(name, i);
  458. ref = jsV_setproperty(J, obj, name);
  459. ref->value = obj->u.a.array[i];
  460. }
  461. js_free(J, obj->u.a.array);
  462. obj->u.a.simple = 0;
  463. obj->u.a.flat_length = 0;
  464. obj->u.a.flat_capacity = 0;
  465. obj->u.a.array = NULL;
  466. js_endtry(J);
  467. }
  468. }
  469. static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name)
  470. {
  471. js_Property *ref;
  472. int k;
  473. if (obj->type == JS_CARRAY) {
  474. if (!strcmp(name, "length")) {
  475. js_pushnumber(J, obj->u.a.length);
  476. return 1;
  477. }
  478. if (obj->u.a.simple) {
  479. if (js_isarrayindex(J, name, &k)) {
  480. if (k >= 0 && k < obj->u.a.flat_length) {
  481. js_pushvalue(J, obj->u.a.array[k]);
  482. return 1;
  483. }
  484. return 0;
  485. }
  486. }
  487. }
  488. else if (obj->type == JS_CSTRING) {
  489. if (!strcmp(name, "length")) {
  490. js_pushnumber(J, obj->u.s.length);
  491. return 1;
  492. }
  493. if (js_isarrayindex(J, name, &k)) {
  494. if (k >= 0 && k < obj->u.s.length) {
  495. js_pushrune(J, js_runeat(J, obj->u.s.string, k));
  496. return 1;
  497. }
  498. }
  499. }
  500. else if (obj->type == JS_CREGEXP) {
  501. if (!strcmp(name, "source")) {
  502. js_pushstring(J, obj->u.r.source);
  503. return 1;
  504. }
  505. if (!strcmp(name, "global")) {
  506. js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G);
  507. return 1;
  508. }
  509. if (!strcmp(name, "ignoreCase")) {
  510. js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I);
  511. return 1;
  512. }
  513. if (!strcmp(name, "multiline")) {
  514. js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M);
  515. return 1;
  516. }
  517. if (!strcmp(name, "lastIndex")) {
  518. js_pushnumber(J, obj->u.r.last);
  519. return 1;
  520. }
  521. }
  522. else if (obj->type == JS_CUSERDATA) {
  523. if (obj->u.user.has && obj->u.user.has(J, obj->u.user.data, name))
  524. return 1;
  525. }
  526. ref = jsV_getproperty(J, obj, name);
  527. if (ref) {
  528. if (ref->getter) {
  529. js_pushobject(J, ref->getter);
  530. js_pushobject(J, obj);
  531. js_call(J, 0);
  532. } else {
  533. js_pushvalue(J, ref->value);
  534. }
  535. return 1;
  536. }
  537. return 0;
  538. }
  539. static void jsR_getproperty(js_State *J, js_Object *obj, const char *name)
  540. {
  541. if (!jsR_hasproperty(J, obj, name))
  542. js_pushundefined(J);
  543. }
  544. static int jsR_hasindex(js_State *J, js_Object *obj, int k)
  545. {
  546. char buf[32];
  547. if (obj->type == JS_CARRAY && obj->u.a.simple) {
  548. if (k >= 0 && k < obj->u.a.flat_length) {
  549. js_pushvalue(J, obj->u.a.array[k]);
  550. return 1;
  551. }
  552. return 0;
  553. }
  554. return jsR_hasproperty(J, obj, js_itoa(buf, k));
  555. }
  556. static void jsR_getindex(js_State *J, js_Object *obj, int k)
  557. {
  558. if (!jsR_hasindex(J, obj, k))
  559. js_pushundefined(J);
  560. }
  561. static void jsR_setarrayindex(js_State *J, js_Object *obj, int k, js_Value *value)
  562. {
  563. int newlen = k + 1;
  564. assert(obj->u.a.simple);
  565. assert(k >= 0);
  566. if (newlen > JS_ARRAYLIMIT)
  567. js_rangeerror(J, "array too large");
  568. if (newlen > obj->u.a.flat_length) {
  569. assert(newlen == obj->u.a.flat_length + 1);
  570. if (newlen > obj->u.a.flat_capacity) {
  571. int newcap = obj->u.a.flat_capacity;
  572. if (newcap == 0)
  573. newcap = 8;
  574. while (newcap < newlen)
  575. newcap <<= 1;
  576. obj->u.a.array = js_realloc(J, obj->u.a.array, newcap * sizeof(js_Value));
  577. obj->u.a.flat_capacity = newcap;
  578. }
  579. obj->u.a.flat_length = newlen;
  580. }
  581. if (newlen > obj->u.a.length)
  582. obj->u.a.length = newlen;
  583. obj->u.a.array[k] = *value;
  584. }
  585. static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, int transient)
  586. {
  587. js_Value *value = stackidx(J, -1);
  588. js_Property *ref;
  589. int k;
  590. int own;
  591. if (obj->type == JS_CARRAY) {
  592. if (!strcmp(name, "length")) {
  593. double rawlen = jsV_tonumber(J, value);
  594. int newlen = jsV_numbertointeger(rawlen);
  595. if (newlen != rawlen || newlen < 0)
  596. js_rangeerror(J, "invalid array length");
  597. if (newlen > JS_ARRAYLIMIT)
  598. js_rangeerror(J, "array too large");
  599. if (obj->u.a.simple) {
  600. obj->u.a.length = newlen;
  601. if (newlen <= obj->u.a.flat_length)
  602. obj->u.a.flat_length = newlen;
  603. } else {
  604. jsV_resizearray(J, obj, newlen);
  605. }
  606. return;
  607. }
  608. if (js_isarrayindex(J, name, &k)) {
  609. if (obj->u.a.simple) {
  610. if (k >= 0 && k <= obj->u.a.flat_length) {
  611. jsR_setarrayindex(J, obj, k, value);
  612. } else {
  613. jsR_unflattenarray(J, obj);
  614. if (obj->u.a.length < k + 1)
  615. obj->u.a.length = k + 1;
  616. }
  617. } else {
  618. if (obj->u.a.length < k + 1)
  619. obj->u.a.length = k + 1;
  620. }
  621. }
  622. }
  623. else if (obj->type == JS_CSTRING) {
  624. if (!strcmp(name, "length"))
  625. goto readonly;
  626. if (js_isarrayindex(J, name, &k))
  627. if (k >= 0 && k < obj->u.s.length)
  628. goto readonly;
  629. }
  630. else if (obj->type == JS_CREGEXP) {
  631. if (!strcmp(name, "source")) goto readonly;
  632. if (!strcmp(name, "global")) goto readonly;
  633. if (!strcmp(name, "ignoreCase")) goto readonly;
  634. if (!strcmp(name, "multiline")) goto readonly;
  635. if (!strcmp(name, "lastIndex")) {
  636. obj->u.r.last = jsV_tointeger(J, value);
  637. return;
  638. }
  639. }
  640. else if (obj->type == JS_CUSERDATA) {
  641. if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
  642. return;
  643. }
  644. /* First try to find a setter in prototype chain */
  645. ref = jsV_getpropertyx(J, obj, name, &own);
  646. if (ref) {
  647. if (ref->setter) {
  648. js_pushobject(J, ref->setter);
  649. js_pushobject(J, obj);
  650. js_pushvalue(J, *value);
  651. js_call(J, 1);
  652. js_pop(J, 1);
  653. return;
  654. } else {
  655. if (J->strict)
  656. if (ref->getter)
  657. js_typeerror(J, "setting property '%s' that only has a getter", name);
  658. if (ref->atts & JS_READONLY)
  659. goto readonly;
  660. }
  661. }
  662. /* Property not found on this object, so create one */
  663. if (!ref || !own) {
  664. if (transient) {
  665. if (J->strict)
  666. js_typeerror(J, "cannot create property '%s' on transient object", name);
  667. return;
  668. }
  669. ref = jsV_setproperty(J, obj, name);
  670. }
  671. if (ref) {
  672. if (!(ref->atts & JS_READONLY))
  673. ref->value = *value;
  674. else
  675. goto readonly;
  676. }
  677. return;
  678. readonly:
  679. if (J->strict)
  680. js_typeerror(J, "'%s' is read-only", name);
  681. }
  682. static void jsR_setindex(js_State *J, js_Object *obj, int k, int transient)
  683. {
  684. char buf[32];
  685. if (obj->type == JS_CARRAY && obj->u.a.simple && k >= 0 && k <= obj->u.a.flat_length) {
  686. jsR_setarrayindex(J, obj, k, stackidx(J, -1));
  687. } else {
  688. jsR_setproperty(J, obj, js_itoa(buf, k), transient);
  689. }
  690. }
  691. static void jsR_defproperty(js_State *J, js_Object *obj, const char *name,
  692. int atts, js_Value *value, js_Object *getter, js_Object *setter,
  693. int throw)
  694. {
  695. js_Property *ref;
  696. int k;
  697. if (obj->type == JS_CARRAY) {
  698. if (!strcmp(name, "length"))
  699. goto readonly;
  700. if (obj->u.a.simple)
  701. jsR_unflattenarray(J, obj);
  702. }
  703. else if (obj->type == JS_CSTRING) {
  704. if (!strcmp(name, "length"))
  705. goto readonly;
  706. if (js_isarrayindex(J, name, &k))
  707. if (k >= 0 && k < obj->u.s.length)
  708. goto readonly;
  709. }
  710. else if (obj->type == JS_CREGEXP) {
  711. if (!strcmp(name, "source")) goto readonly;
  712. if (!strcmp(name, "global")) goto readonly;
  713. if (!strcmp(name, "ignoreCase")) goto readonly;
  714. if (!strcmp(name, "multiline")) goto readonly;
  715. if (!strcmp(name, "lastIndex")) goto readonly;
  716. }
  717. else if (obj->type == JS_CUSERDATA) {
  718. if (obj->u.user.put && obj->u.user.put(J, obj->u.user.data, name))
  719. return;
  720. }
  721. ref = jsV_setproperty(J, obj, name);
  722. if (ref) {
  723. if (value) {
  724. if (!(ref->atts & JS_READONLY))
  725. ref->value = *value;
  726. else if (J->strict)
  727. js_typeerror(J, "'%s' is read-only", name);
  728. }
  729. if (getter) {
  730. if (!(ref->atts & JS_DONTCONF))
  731. ref->getter = getter;
  732. else if (J->strict)
  733. js_typeerror(J, "'%s' is non-configurable", name);
  734. }
  735. if (setter) {
  736. if (!(ref->atts & JS_DONTCONF))
  737. ref->setter = setter;
  738. else if (J->strict)
  739. js_typeerror(J, "'%s' is non-configurable", name);
  740. }
  741. ref->atts |= atts;
  742. }
  743. return;
  744. readonly:
  745. if (J->strict || throw)
  746. js_typeerror(J, "'%s' is read-only or non-configurable", name);
  747. }
  748. static int jsR_delproperty(js_State *J, js_Object *obj, const char *name)
  749. {
  750. js_Property *ref;
  751. int k;
  752. if (obj->type == JS_CARRAY) {
  753. if (!strcmp(name, "length"))
  754. goto dontconf;
  755. if (obj->u.a.simple)
  756. jsR_unflattenarray(J, obj);
  757. }
  758. else if (obj->type == JS_CSTRING) {
  759. if (!strcmp(name, "length"))
  760. goto dontconf;
  761. if (js_isarrayindex(J, name, &k))
  762. if (k >= 0 && k < obj->u.s.length)
  763. goto dontconf;
  764. }
  765. else if (obj->type == JS_CREGEXP) {
  766. if (!strcmp(name, "source")) goto dontconf;
  767. if (!strcmp(name, "global")) goto dontconf;
  768. if (!strcmp(name, "ignoreCase")) goto dontconf;
  769. if (!strcmp(name, "multiline")) goto dontconf;
  770. if (!strcmp(name, "lastIndex")) goto dontconf;
  771. }
  772. else if (obj->type == JS_CUSERDATA) {
  773. if (obj->u.user.delete && obj->u.user.delete(J, obj->u.user.data, name))
  774. return 1;
  775. }
  776. ref = jsV_getownproperty(J, obj, name);
  777. if (ref) {
  778. if (ref->atts & JS_DONTCONF)
  779. goto dontconf;
  780. jsV_delproperty(J, obj, name);
  781. }
  782. return 1;
  783. dontconf:
  784. if (J->strict)
  785. js_typeerror(J, "'%s' is non-configurable", name);
  786. return 0;
  787. }
  788. static void jsR_delindex(js_State *J, js_Object *obj, int k)
  789. {
  790. char buf[32];
  791. /* Allow deleting last element of a simple array without unflattening */
  792. if (obj->type == JS_CARRAY && obj->u.a.simple && k == obj->u.a.flat_length - 1)
  793. obj->u.a.flat_length = k;
  794. else
  795. jsR_delproperty(J, obj, js_itoa(buf, k));
  796. }
  797. /* Registry, global and object property accessors */
  798. const char *js_ref(js_State *J)
  799. {
  800. js_Value *v = stackidx(J, -1);
  801. const char *s;
  802. char buf[32];
  803. switch (v->t.type) {
  804. case JS_TUNDEFINED: s = "_Undefined"; break;
  805. case JS_TNULL: s = "_Null"; break;
  806. case JS_TBOOLEAN:
  807. s = v->u.boolean ? "_True" : "_False";
  808. break;
  809. case JS_TOBJECT:
  810. sprintf(buf, "%p", (void*)v->u.object);
  811. s = js_intern(J, buf);
  812. break;
  813. default:
  814. sprintf(buf, "%d", J->nextref++);
  815. s = js_intern(J, buf);
  816. break;
  817. }
  818. js_setregistry(J, s);
  819. return s;
  820. }
  821. void js_unref(js_State *J, const char *ref)
  822. {
  823. js_delregistry(J, ref);
  824. }
  825. void js_getregistry(js_State *J, const char *name)
  826. {
  827. jsR_getproperty(J, J->R, name);
  828. }
  829. void js_setregistry(js_State *J, const char *name)
  830. {
  831. jsR_setproperty(J, J->R, name, 0);
  832. js_pop(J, 1);
  833. }
  834. void js_delregistry(js_State *J, const char *name)
  835. {
  836. jsR_delproperty(J, J->R, name);
  837. }
  838. void js_getglobal(js_State *J, const char *name)
  839. {
  840. jsR_getproperty(J, J->G, name);
  841. }
  842. void js_setglobal(js_State *J, const char *name)
  843. {
  844. jsR_setproperty(J, J->G, name, 0);
  845. js_pop(J, 1);
  846. }
  847. void js_defglobal(js_State *J, const char *name, int atts)
  848. {
  849. jsR_defproperty(J, J->G, name, atts, stackidx(J, -1), NULL, NULL, 0);
  850. js_pop(J, 1);
  851. }
  852. void js_delglobal(js_State *J, const char *name)
  853. {
  854. jsR_delproperty(J, J->G, name);
  855. }
  856. void js_getproperty(js_State *J, int idx, const char *name)
  857. {
  858. jsR_getproperty(J, js_toobject(J, idx), name);
  859. }
  860. void js_setproperty(js_State *J, int idx, const char *name)
  861. {
  862. jsR_setproperty(J, js_toobject(J, idx), name, !js_isobject(J, idx));
  863. js_pop(J, 1);
  864. }
  865. void js_defproperty(js_State *J, int idx, const char *name, int atts)
  866. {
  867. jsR_defproperty(J, js_toobject(J, idx), name, atts, stackidx(J, -1), NULL, NULL, 1);
  868. js_pop(J, 1);
  869. }
  870. void js_delproperty(js_State *J, int idx, const char *name)
  871. {
  872. jsR_delproperty(J, js_toobject(J, idx), name);
  873. }
  874. void js_defaccessor(js_State *J, int idx, const char *name, int atts)
  875. {
  876. jsR_defproperty(J, js_toobject(J, idx), name, atts, NULL, jsR_tofunction(J, -2), jsR_tofunction(J, -1), 1);
  877. js_pop(J, 2);
  878. }
  879. int js_hasproperty(js_State *J, int idx, const char *name)
  880. {
  881. return jsR_hasproperty(J, js_toobject(J, idx), name);
  882. }
  883. void js_getindex(js_State *J, int idx, int i)
  884. {
  885. jsR_getindex(J, js_toobject(J, idx), i);
  886. }
  887. int js_hasindex(js_State *J, int idx, int i)
  888. {
  889. return jsR_hasindex(J, js_toobject(J, idx), i);
  890. }
  891. void js_setindex(js_State *J, int idx, int i)
  892. {
  893. jsR_setindex(J, js_toobject(J, idx), i, !js_isobject(J, idx));
  894. js_pop(J, 1);
  895. }
  896. void js_delindex(js_State *J, int idx, int i)
  897. {
  898. jsR_delindex(J, js_toobject(J, idx), i);
  899. }
  900. /* Iterator */
  901. void js_pushiterator(js_State *J, int idx, int own)
  902. {
  903. js_pushobject(J, jsV_newiterator(J, js_toobject(J, idx), own));
  904. }
  905. const char *js_nextiterator(js_State *J, int idx)
  906. {
  907. return jsV_nextiterator(J, js_toobject(J, idx));
  908. }
  909. /* Environment records */
  910. js_Environment *jsR_newenvironment(js_State *J, js_Object *vars, js_Environment *outer)
  911. {
  912. js_Environment *E = js_malloc(J, sizeof *E);
  913. E->gcmark = 0;
  914. E->gcnext = J->gcenv;
  915. J->gcenv = E;
  916. ++J->gccounter;
  917. E->outer = outer;
  918. E->variables = vars;
  919. return E;
  920. }
  921. static void js_initvar(js_State *J, const char *name, int idx)
  922. {
  923. jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, stackidx(J, idx), NULL, NULL, 0);
  924. }
  925. static int js_hasvar(js_State *J, const char *name)
  926. {
  927. js_Environment *E = J->E;
  928. do {
  929. js_Property *ref = jsV_getproperty(J, E->variables, name);
  930. if (ref) {
  931. if (ref->getter) {
  932. js_pushobject(J, ref->getter);
  933. js_pushobject(J, E->variables);
  934. js_call(J, 0);
  935. } else {
  936. js_pushvalue(J, ref->value);
  937. }
  938. return 1;
  939. }
  940. E = E->outer;
  941. } while (E);
  942. return 0;
  943. }
  944. static void js_setvar(js_State *J, const char *name)
  945. {
  946. js_Environment *E = J->E;
  947. do {
  948. js_Property *ref = jsV_getproperty(J, E->variables, name);
  949. if (ref) {
  950. if (ref->setter) {
  951. js_pushobject(J, ref->setter);
  952. js_pushobject(J, E->variables);
  953. js_copy(J, -3);
  954. js_call(J, 1);
  955. js_pop(J, 1);
  956. return;
  957. }
  958. if (!(ref->atts & JS_READONLY))
  959. ref->value = *stackidx(J, -1);
  960. else if (J->strict)
  961. js_typeerror(J, "'%s' is read-only", name);
  962. return;
  963. }
  964. E = E->outer;
  965. } while (E);
  966. if (J->strict)
  967. js_referenceerror(J, "assignment to undeclared variable '%s'", name);
  968. jsR_setproperty(J, J->G, name, 0);
  969. }
  970. static int js_delvar(js_State *J, const char *name)
  971. {
  972. js_Environment *E = J->E;
  973. do {
  974. js_Property *ref = jsV_getownproperty(J, E->variables, name);
  975. if (ref) {
  976. if (ref->atts & JS_DONTCONF) {
  977. if (J->strict)
  978. js_typeerror(J, "'%s' is non-configurable", name);
  979. return 0;
  980. }
  981. jsV_delproperty(J, E->variables, name);
  982. return 1;
  983. }
  984. E = E->outer;
  985. } while (E);
  986. return jsR_delproperty(J, J->G, name);
  987. }
  988. /* Function calls */
  989. static void jsR_savescope(js_State *J, js_Environment *newE)
  990. {
  991. if (J->envtop + 1 >= JS_ENVLIMIT)
  992. js_stackoverflow(J);
  993. J->envstack[J->envtop++] = J->E;
  994. J->E = newE;
  995. }
  996. static void jsR_restorescope(js_State *J)
  997. {
  998. J->E = J->envstack[--J->envtop];
  999. }
  1000. static void jsR_calllwfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
  1001. {
  1002. js_Value v;
  1003. int i;
  1004. jsR_savescope(J, scope);
  1005. if (n > F->numparams) {
  1006. js_pop(J, n - F->numparams);
  1007. n = F->numparams;
  1008. }
  1009. for (i = n; i < F->varlen; ++i)
  1010. js_pushundefined(J);
  1011. jsR_run(J, F);
  1012. v = *stackidx(J, -1);
  1013. TOP = --BOT; /* clear stack */
  1014. js_pushvalue(J, v);
  1015. jsR_restorescope(J);
  1016. }
  1017. static void jsR_callfunction(js_State *J, int n, js_Function *F, js_Environment *scope)
  1018. {
  1019. js_Value v;
  1020. int i;
  1021. scope = jsR_newenvironment(J, jsV_newobject(J, JS_COBJECT, NULL), scope);
  1022. jsR_savescope(J, scope);
  1023. if (F->arguments) {
  1024. js_newarguments(J);
  1025. if (!J->strict) {
  1026. js_currentfunction(J);
  1027. js_defproperty(J, -2, "callee", JS_DONTENUM);
  1028. }
  1029. js_pushnumber(J, n);
  1030. js_defproperty(J, -2, "length", JS_DONTENUM);
  1031. for (i = 0; i < n; ++i) {
  1032. js_copy(J, i + 1);
  1033. js_setindex(J, -2, i);
  1034. }
  1035. js_initvar(J, "arguments", -1);
  1036. js_pop(J, 1);
  1037. }
  1038. for (i = 0; i < n && i < F->numparams; ++i)
  1039. js_initvar(J, F->vartab[i], i + 1);
  1040. js_pop(J, n);
  1041. for (; i < F->varlen; ++i) {
  1042. js_pushundefined(J);
  1043. js_initvar(J, F->vartab[i], -1);
  1044. js_pop(J, 1);
  1045. }
  1046. jsR_run(J, F);
  1047. v = *stackidx(J, -1);
  1048. TOP = --BOT; /* clear stack */
  1049. js_pushvalue(J, v);
  1050. jsR_restorescope(J);
  1051. }
  1052. static void jsR_callscript(js_State *J, int n, js_Function *F, js_Environment *scope)
  1053. {
  1054. js_Value v;
  1055. int i;
  1056. if (scope)
  1057. jsR_savescope(J, scope);
  1058. /* scripts take no arguments */
  1059. js_pop(J, n);
  1060. for (i = 0; i < F->varlen; ++i) {
  1061. /* Bug 701886: don't redefine existing vars in eval/scripts */
  1062. if (!js_hasvar(J, F->vartab[i])) {
  1063. js_pushundefined(J);
  1064. js_initvar(J, F->vartab[i], -1);
  1065. js_pop(J, 1);
  1066. }
  1067. }
  1068. jsR_run(J, F);
  1069. v = *stackidx(J, -1);
  1070. TOP = --BOT; /* clear stack */
  1071. js_pushvalue(J, v);
  1072. if (scope)
  1073. jsR_restorescope(J);
  1074. }
  1075. static void jsR_callcfunction(js_State *J, int n, int min, js_CFunction F)
  1076. {
  1077. int save_top;
  1078. int i;
  1079. js_Value v;
  1080. for (i = n; i < min; ++i)
  1081. js_pushundefined(J);
  1082. save_top = TOP;
  1083. F(J);
  1084. if (TOP > save_top) {
  1085. v = *stackidx(J, -1);
  1086. TOP = --BOT; /* clear stack */
  1087. js_pushvalue(J, v);
  1088. } else {
  1089. TOP = --BOT; /* clear stack */
  1090. js_pushundefined(J);
  1091. }
  1092. }
  1093. static void jsR_pushtrace(js_State *J, const char *name, const char *file, int line)
  1094. {
  1095. if (J->tracetop + 1 == JS_ENVLIMIT)
  1096. js_error(J, "call stack overflow");
  1097. ++J->tracetop;
  1098. J->trace[J->tracetop].name = name;
  1099. J->trace[J->tracetop].file = file;
  1100. J->trace[J->tracetop].line = line;
  1101. }
  1102. void js_call(js_State *J, int n)
  1103. {
  1104. js_Object *obj;
  1105. int savebot;
  1106. if (n < 0)
  1107. js_rangeerror(J, "number of arguments cannot be negative");
  1108. if (!js_iscallable(J, -n-2))
  1109. js_typeerror(J, "%s is not callable", js_typeof(J, -n-2));
  1110. obj = js_toobject(J, -n-2);
  1111. savebot = BOT;
  1112. BOT = TOP - n - 1;
  1113. if (obj->type == JS_CFUNCTION) {
  1114. jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
  1115. if (obj->u.f.function->lightweight)
  1116. jsR_calllwfunction(J, n, obj->u.f.function, obj->u.f.scope);
  1117. else
  1118. jsR_callfunction(J, n, obj->u.f.function, obj->u.f.scope);
  1119. --J->tracetop;
  1120. } else if (obj->type == JS_CSCRIPT) {
  1121. jsR_pushtrace(J, obj->u.f.function->name, obj->u.f.function->filename, obj->u.f.function->line);
  1122. jsR_callscript(J, n, obj->u.f.function, obj->u.f.scope);
  1123. --J->tracetop;
  1124. } else if (obj->type == JS_CCFUNCTION) {
  1125. jsR_pushtrace(J, obj->u.c.name, "native", 0);
  1126. jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.function);
  1127. --J->tracetop;
  1128. }
  1129. BOT = savebot;
  1130. }
  1131. void js_construct(js_State *J, int n)
  1132. {
  1133. js_Object *obj;
  1134. js_Object *prototype;
  1135. js_Object *newobj;
  1136. if (!js_iscallable(J, -n-1))
  1137. js_typeerror(J, "%s is not callable", js_typeof(J, -n-1));
  1138. obj = js_toobject(J, -n-1);
  1139. /* built-in constructors create their own objects, give them a 'null' this */
  1140. if (obj->type == JS_CCFUNCTION && obj->u.c.constructor) {
  1141. int savebot = BOT;
  1142. js_pushnull(J);
  1143. if (n > 0)
  1144. js_rot(J, n + 1);
  1145. BOT = TOP - n - 1;
  1146. jsR_pushtrace(J, obj->u.c.name, "native", 0);
  1147. jsR_callcfunction(J, n, obj->u.c.length, obj->u.c.constructor);
  1148. --J->tracetop;
  1149. BOT = savebot;
  1150. return;
  1151. }
  1152. /* extract the function object's prototype property */
  1153. js_getproperty(J, -n - 1, "prototype");
  1154. if (js_isobject(J, -1))
  1155. prototype = js_toobject(J, -1);
  1156. else
  1157. prototype = J->Object_prototype;
  1158. js_pop(J, 1);
  1159. /* create a new object with above prototype, and shift it into the 'this' slot */
  1160. newobj = jsV_newobject(J, JS_COBJECT, prototype);
  1161. js_pushobject(J, newobj);
  1162. if (n > 0)
  1163. js_rot(J, n + 1);
  1164. /* and save a copy to return */
  1165. js_pushobject(J, newobj);
  1166. js_rot(J, n + 3);
  1167. /* call the function */
  1168. js_call(J, n);
  1169. /* if result is not an object, return the original object we created */
  1170. if (!js_isobject(J, -1)) {
  1171. js_pop(J, 1);
  1172. } else {
  1173. js_rot2pop1(J);
  1174. }
  1175. }
  1176. void js_eval(js_State *J)
  1177. {
  1178. if (!js_isstring(J, -1))
  1179. return;
  1180. js_loadeval(J, "(eval)", js_tostring(J, -1));
  1181. js_rot2pop1(J);
  1182. js_copy(J, 0); /* copy 'this' */
  1183. js_call(J, 0);
  1184. }
  1185. int js_pconstruct(js_State *J, int n)
  1186. {
  1187. int savetop = TOP - n - 2;
  1188. if (js_try(J)) {
  1189. /* clean up the stack to only hold the error object */
  1190. STACK[savetop] = STACK[TOP-1];
  1191. TOP = savetop + 1;
  1192. return 1;
  1193. }
  1194. js_construct(J, n);
  1195. js_endtry(J);
  1196. return 0;
  1197. }
  1198. int js_pcall(js_State *J, int n)
  1199. {
  1200. int savetop = TOP - n - 2;
  1201. if (js_try(J)) {
  1202. /* clean up the stack to only hold the error object */
  1203. STACK[savetop] = STACK[TOP-1];
  1204. TOP = savetop + 1;
  1205. return 1;
  1206. }
  1207. js_call(J, n);
  1208. js_endtry(J);
  1209. return 0;
  1210. }
  1211. /* Exceptions */
  1212. void *js_savetrypc(js_State *J, js_Instruction *pc)
  1213. {
  1214. if (J->trytop == JS_TRYLIMIT)
  1215. js_trystackoverflow(J);
  1216. J->trybuf[J->trytop].E = J->E;
  1217. J->trybuf[J->trytop].envtop = J->envtop;
  1218. J->trybuf[J->trytop].tracetop = J->tracetop;
  1219. J->trybuf[J->trytop].top = J->top;
  1220. J->trybuf[J->trytop].bot = J->bot;
  1221. J->trybuf[J->trytop].strict = J->strict;
  1222. J->trybuf[J->trytop].pc = pc;
  1223. return J->trybuf[J->trytop++].buf;
  1224. }
  1225. void *js_savetry(js_State *J)
  1226. {
  1227. if (J->trytop == JS_TRYLIMIT)
  1228. js_trystackoverflow(J);
  1229. J->trybuf[J->trytop].E = J->E;
  1230. J->trybuf[J->trytop].envtop = J->envtop;
  1231. J->trybuf[J->trytop].tracetop = J->tracetop;
  1232. J->trybuf[J->trytop].top = J->top;
  1233. J->trybuf[J->trytop].bot = J->bot;
  1234. J->trybuf[J->trytop].strict = J->strict;
  1235. J->trybuf[J->trytop].pc = NULL;
  1236. return J->trybuf[J->trytop++].buf;
  1237. }
  1238. void js_endtry(js_State *J)
  1239. {
  1240. if (J->trytop == 0)
  1241. js_error(J, "endtry: exception stack underflow");
  1242. --J->trytop;
  1243. }
  1244. void js_throw(js_State *J)
  1245. {
  1246. if (J->trytop > 0) {
  1247. js_Value v = *stackidx(J, -1);
  1248. --J->trytop;
  1249. J->E = J->trybuf[J->trytop].E;
  1250. J->envtop = J->trybuf[J->trytop].envtop;
  1251. J->tracetop = J->trybuf[J->trytop].tracetop;
  1252. J->top = J->trybuf[J->trytop].top;
  1253. J->bot = J->trybuf[J->trytop].bot;
  1254. J->strict = J->trybuf[J->trytop].strict;
  1255. js_pushvalue(J, v);
  1256. longjmp(J->trybuf[J->trytop].buf, 1);
  1257. }
  1258. if (J->panic)
  1259. J->panic(J);
  1260. abort();
  1261. }
  1262. /* Main interpreter loop */
  1263. static void js_dumpvalue(js_State *J, js_Value v)
  1264. {
  1265. switch (v.t.type) {
  1266. case JS_TUNDEFINED: printf("undefined"); break;
  1267. case JS_TNULL: printf("null"); break;
  1268. case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
  1269. case JS_TNUMBER: printf("%.9g", v.u.number); break;
  1270. case JS_TSHRSTR: printf("'%s'", v.u.shrstr); break;
  1271. case JS_TLITSTR: printf("'%s'", v.u.litstr); break;
  1272. case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break;
  1273. case JS_TOBJECT:
  1274. if (v.u.object == J->G) {
  1275. printf("[Global]");
  1276. break;
  1277. }
  1278. switch (v.u.object->type) {
  1279. case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break;
  1280. case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break;
  1281. case JS_CFUNCTION:
  1282. printf("[Function %p, %s, %s:%d]",
  1283. (void*)v.u.object,
  1284. v.u.object->u.f.function->name,
  1285. v.u.object->u.f.function->filename,
  1286. v.u.object->u.f.function->line);
  1287. break;
  1288. case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break;
  1289. case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break;
  1290. case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
  1291. case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
  1292. case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
  1293. case JS_CERROR: printf("[Error]"); break;
  1294. case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break;
  1295. case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break;
  1296. case JS_CUSERDATA:
  1297. printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
  1298. break;
  1299. default: printf("[Object %p]", (void*)v.u.object); break;
  1300. }
  1301. break;
  1302. }
  1303. }
  1304. static void js_stacktrace(js_State *J)
  1305. {
  1306. int n;
  1307. printf("stack trace:\n");
  1308. for (n = J->tracetop; n >= 0; --n) {
  1309. const char *name = J->trace[n].name;
  1310. const char *file = J->trace[n].file;
  1311. int line = J->trace[n].line;
  1312. if (line > 0) {
  1313. if (name[0])
  1314. printf("\tat %s (%s:%d)\n", name, file, line);
  1315. else
  1316. printf("\tat %s:%d\n", file, line);
  1317. } else
  1318. printf("\tat %s (%s)\n", name, file);
  1319. }
  1320. }
  1321. static void js_dumpstack(js_State *J)
  1322. {
  1323. int i;
  1324. printf("stack {\n");
  1325. for (i = 0; i < TOP; ++i) {
  1326. putchar(i == BOT ? '>' : ' ');
  1327. printf("%4d: ", i);
  1328. js_dumpvalue(J, STACK[i]);
  1329. putchar('\n');
  1330. }
  1331. printf("}\n");
  1332. }
  1333. void js_trap(js_State *J, int pc)
  1334. {
  1335. js_dumpstack(J);
  1336. js_stacktrace(J);
  1337. }
  1338. static int jsR_isindex(js_State *J, int idx, int *k)
  1339. {
  1340. js_Value *v = stackidx(J, idx);
  1341. if (v->t.type == JS_TNUMBER) {
  1342. *k = v->u.number;
  1343. return *k == v->u.number && *k >= 0;
  1344. }
  1345. return 0;
  1346. }
  1347. static void jsR_run(js_State *J, js_Function *F)
  1348. {
  1349. js_Function **FT = F->funtab;
  1350. const char **VT = F->vartab-1;
  1351. int lightweight = F->lightweight;
  1352. js_Instruction *pcstart = F->code;
  1353. js_Instruction *pc = F->code;
  1354. enum js_OpCode opcode;
  1355. int offset;
  1356. int savestrict;
  1357. const char *str;
  1358. js_Object *obj;
  1359. double x, y;
  1360. unsigned int ux, uy;
  1361. int ix, iy, okay;
  1362. int b;
  1363. int transient;
  1364. savestrict = J->strict;
  1365. J->strict = F->strict;
  1366. #define READSTRING() \
  1367. memcpy(&str, pc, sizeof(str)); \
  1368. pc += sizeof(str) / sizeof(*pc)
  1369. while (1) {
  1370. if (J->gccounter > J->gcthresh)
  1371. js_gc(J, 0);
  1372. J->trace[J->tracetop].line = *pc++;
  1373. opcode = *pc++;
  1374. switch (opcode) {
  1375. case OP_POP: js_pop(J, 1); break;
  1376. case OP_DUP: js_dup(J); break;
  1377. case OP_DUP2: js_dup2(J); break;
  1378. case OP_ROT2: js_rot2(J); break;
  1379. case OP_ROT3: js_rot3(J); break;
  1380. case OP_ROT4: js_rot4(J); break;
  1381. case OP_INTEGER:
  1382. js_pushnumber(J, *pc++ - 32768);
  1383. break;
  1384. case OP_NUMBER:
  1385. memcpy(&x, pc, sizeof(x));
  1386. pc += sizeof(x) / sizeof(*pc);
  1387. js_pushnumber(J, x);
  1388. break;
  1389. case OP_STRING:
  1390. READSTRING();
  1391. js_pushliteral(J, str);
  1392. break;
  1393. case OP_CLOSURE: js_newfunction(J, FT[*pc++], J->E); break;
  1394. case OP_NEWOBJECT: js_newobject(J); break;
  1395. case OP_NEWARRAY: js_newarray(J); break;
  1396. case OP_NEWREGEXP:
  1397. READSTRING();
  1398. js_newregexp(J, str, *pc++);
  1399. break;
  1400. case OP_UNDEF: js_pushundefined(J); break;
  1401. case OP_NULL: js_pushnull(J); break;
  1402. case OP_TRUE: js_pushboolean(J, 1); break;
  1403. case OP_FALSE: js_pushboolean(J, 0); break;
  1404. case OP_THIS:
  1405. if (J->strict) {
  1406. js_copy(J, 0);
  1407. } else {
  1408. if (js_iscoercible(J, 0))
  1409. js_copy(J, 0);
  1410. else
  1411. js_pushglobal(J);
  1412. }
  1413. break;
  1414. case OP_CURRENT:
  1415. js_currentfunction(J);
  1416. break;
  1417. case OP_GETLOCAL:
  1418. if (lightweight) {
  1419. CHECKSTACK(1);
  1420. STACK[TOP++] = STACK[BOT + *pc++];
  1421. } else {
  1422. str = VT[*pc++];
  1423. if (!js_hasvar(J, str))
  1424. js_referenceerror(J, "'%s' is not defined", str);
  1425. }
  1426. break;
  1427. case OP_SETLOCAL:
  1428. if (lightweight) {
  1429. STACK[BOT + *pc++] = STACK[TOP-1];
  1430. } else {
  1431. js_setvar(J, VT[*pc++]);
  1432. }
  1433. break;
  1434. case OP_DELLOCAL:
  1435. if (lightweight) {
  1436. ++pc;
  1437. js_pushboolean(J, 0);
  1438. } else {
  1439. b = js_delvar(J, VT[*pc++]);
  1440. js_pushboolean(J, b);
  1441. }
  1442. break;
  1443. case OP_GETVAR:
  1444. READSTRING();
  1445. if (!js_hasvar(J, str))
  1446. js_referenceerror(J, "'%s' is not defined", str);
  1447. break;
  1448. case OP_HASVAR:
  1449. READSTRING();
  1450. if (!js_hasvar(J, str))
  1451. js_pushundefined(J);
  1452. break;
  1453. case OP_SETVAR:
  1454. READSTRING();
  1455. js_setvar(J, str);
  1456. break;
  1457. case OP_DELVAR:
  1458. READSTRING();
  1459. b = js_delvar(J, str);
  1460. js_pushboolean(J, b);
  1461. break;
  1462. case OP_IN:
  1463. str = js_tostring(J, -2);
  1464. if (!js_isobject(J, -1))
  1465. js_typeerror(J, "operand to 'in' is not an object");
  1466. b = js_hasproperty(J, -1, str);
  1467. js_pop(J, 2 + b);
  1468. js_pushboolean(J, b);
  1469. break;
  1470. case OP_SKIPARRAY:
  1471. js_setlength(J, -1, js_getlength(J, -1) + 1);
  1472. break;
  1473. case OP_INITARRAY:
  1474. js_setindex(J, -2, js_getlength(J, -2));
  1475. break;
  1476. case OP_INITPROP:
  1477. obj = js_toobject(J, -3);
  1478. str = js_tostring(J, -2);
  1479. jsR_setproperty(J, obj, str, 0);
  1480. js_pop(J, 2);
  1481. break;
  1482. case OP_INITGETTER:
  1483. obj = js_toobject(J, -3);
  1484. str = js_tostring(J, -2);
  1485. jsR_defproperty(J, obj, str, 0, NULL, jsR_tofunction(J, -1), NULL, 0);
  1486. js_pop(J, 2);
  1487. break;
  1488. case OP_INITSETTER:
  1489. obj = js_toobject(J, -3);
  1490. str = js_tostring(J, -2);
  1491. jsR_defproperty(J, obj, str, 0, NULL, NULL, jsR_tofunction(J, -1), 0);
  1492. js_pop(J, 2);
  1493. break;
  1494. case OP_GETPROP:
  1495. if (jsR_isindex(J, -1, &ix)) {
  1496. obj = js_toobject(J, -2);
  1497. jsR_getindex(J, obj, ix);
  1498. } else {
  1499. str = js_tostring(J, -1);
  1500. obj = js_toobject(J, -2);
  1501. jsR_getproperty(J, obj, str);
  1502. }
  1503. js_rot3pop2(J);
  1504. break;
  1505. case OP_GETPROP_S:
  1506. READSTRING();
  1507. obj = js_toobject(J, -1);
  1508. jsR_getproperty(J, obj, str);
  1509. js_rot2pop1(J);
  1510. break;
  1511. case OP_SETPROP:
  1512. if (jsR_isindex(J, -2, &ix)) {
  1513. obj = js_toobject(J, -3);
  1514. transient = !js_isobject(J, -3);
  1515. jsR_setindex(J, obj, ix, transient);
  1516. } else {
  1517. str = js_tostring(J, -2);
  1518. obj = js_toobject(J, -3);
  1519. transient = !js_isobject(J, -3);
  1520. jsR_setproperty(J, obj, str, transient);
  1521. }
  1522. js_rot3pop2(J);
  1523. break;
  1524. case OP_SETPROP_S:
  1525. READSTRING();
  1526. obj = js_toobject(J, -2);
  1527. transient = !js_isobject(J, -2);
  1528. jsR_setproperty(J, obj, str, transient);
  1529. js_rot2pop1(J);
  1530. break;
  1531. case OP_DELPROP:
  1532. str = js_tostring(J, -1);
  1533. obj = js_toobject(J, -2);
  1534. b = jsR_delproperty(J, obj, str);
  1535. js_pop(J, 2);
  1536. js_pushboolean(J, b);
  1537. break;
  1538. case OP_DELPROP_S:
  1539. READSTRING();
  1540. obj = js_toobject(J, -1);
  1541. b = jsR_delproperty(J, obj, str);
  1542. js_pop(J, 1);
  1543. js_pushboolean(J, b);
  1544. break;
  1545. case OP_ITERATOR:
  1546. if (js_iscoercible(J, -1)) {
  1547. obj = jsV_newiterator(J, js_toobject(J, -1), 0);
  1548. js_pop(J, 1);
  1549. js_pushobject(J, obj);
  1550. }
  1551. break;
  1552. case OP_NEXTITER:
  1553. if (js_isobject(J, -1)) {
  1554. obj = js_toobject(J, -1);
  1555. str = jsV_nextiterator(J, obj);
  1556. if (str) {
  1557. js_pushstring(J, str);
  1558. js_pushboolean(J, 1);
  1559. } else {
  1560. js_pop(J, 1);
  1561. js_pushboolean(J, 0);
  1562. }
  1563. } else {
  1564. js_pop(J, 1);
  1565. js_pushboolean(J, 0);
  1566. }
  1567. break;
  1568. /* Function calls */
  1569. case OP_EVAL:
  1570. js_eval(J);
  1571. break;
  1572. case OP_CALL:
  1573. js_call(J, *pc++);
  1574. break;
  1575. case OP_NEW:
  1576. js_construct(J, *pc++);
  1577. break;
  1578. /* Unary operators */
  1579. case OP_TYPEOF:
  1580. str = js_typeof(J, -1);
  1581. js_pop(J, 1);
  1582. js_pushliteral(J, str);
  1583. break;
  1584. case OP_POS:
  1585. x = js_tonumber(J, -1);
  1586. js_pop(J, 1);
  1587. js_pushnumber(J, x);
  1588. break;
  1589. case OP_NEG:
  1590. x = js_tonumber(J, -1);
  1591. js_pop(J, 1);
  1592. js_pushnumber(J, -x);
  1593. break;
  1594. case OP_BITNOT:
  1595. ix = js_toint32(J, -1);
  1596. js_pop(J, 1);
  1597. js_pushnumber(J, ~ix);
  1598. break;
  1599. case OP_LOGNOT:
  1600. b = js_toboolean(J, -1);
  1601. js_pop(J, 1);
  1602. js_pushboolean(J, !b);
  1603. break;
  1604. case OP_INC:
  1605. x = js_tonumber(J, -1);
  1606. js_pop(J, 1);
  1607. js_pushnumber(J, x + 1);
  1608. break;
  1609. case OP_DEC:
  1610. x = js_tonumber(J, -1);
  1611. js_pop(J, 1);
  1612. js_pushnumber(J, x - 1);
  1613. break;
  1614. case OP_POSTINC:
  1615. x = js_tonumber(J, -1);
  1616. js_pop(J, 1);
  1617. js_pushnumber(J, x + 1);
  1618. js_pushnumber(J, x);
  1619. break;
  1620. case OP_POSTDEC:
  1621. x = js_tonumber(J, -1);
  1622. js_pop(J, 1);
  1623. js_pushnumber(J, x - 1);
  1624. js_pushnumber(J, x);
  1625. break;
  1626. /* Multiplicative operators */
  1627. case OP_MUL:
  1628. x = js_tonumber(J, -2);
  1629. y = js_tonumber(J, -1);
  1630. js_pop(J, 2);
  1631. js_pushnumber(J, x * y);
  1632. break;
  1633. case OP_DIV:
  1634. x = js_tonumber(J, -2);
  1635. y = js_tonumber(J, -1);
  1636. js_pop(J, 2);
  1637. js_pushnumber(J, x / y);
  1638. break;
  1639. case OP_MOD:
  1640. x = js_tonumber(J, -2);
  1641. y = js_tonumber(J, -1);
  1642. js_pop(J, 2);
  1643. js_pushnumber(J, fmod(x, y));
  1644. break;
  1645. /* Additive operators */
  1646. case OP_ADD:
  1647. js_concat(J);
  1648. break;
  1649. case OP_SUB:
  1650. x = js_tonumber(J, -2);
  1651. y = js_tonumber(J, -1);
  1652. js_pop(J, 2);
  1653. js_pushnumber(J, x - y);
  1654. break;
  1655. /* Shift operators */
  1656. case OP_SHL:
  1657. ix = js_toint32(J, -2);
  1658. uy = js_touint32(J, -1);
  1659. js_pop(J, 2);
  1660. js_pushnumber(J, ix << (uy & 0x1F));
  1661. break;
  1662. case OP_SHR:
  1663. ix = js_toint32(J, -2);
  1664. uy = js_touint32(J, -1);
  1665. js_pop(J, 2);
  1666. js_pushnumber(J, ix >> (uy & 0x1F));
  1667. break;
  1668. case OP_USHR:
  1669. ux = js_touint32(J, -2);
  1670. uy = js_touint32(J, -1);
  1671. js_pop(J, 2);
  1672. js_pushnumber(J, ux >> (uy & 0x1F));
  1673. break;
  1674. /* Relational operators */
  1675. case OP_LT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b < 0); break;
  1676. case OP_GT: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b > 0); break;
  1677. case OP_LE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b <= 0); break;
  1678. case OP_GE: b = js_compare(J, &okay); js_pop(J, 2); js_pushboolean(J, okay && b >= 0); break;
  1679. case OP_INSTANCEOF:
  1680. b = js_instanceof(J);
  1681. js_pop(J, 2);
  1682. js_pushboolean(J, b);
  1683. break;
  1684. /* Equality */
  1685. case OP_EQ: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, b); break;
  1686. case OP_NE: b = js_equal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
  1687. case OP_STRICTEQ: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, b); break;
  1688. case OP_STRICTNE: b = js_strictequal(J); js_pop(J, 2); js_pushboolean(J, !b); break;
  1689. case OP_JCASE:
  1690. offset = *pc++;
  1691. b = js_strictequal(J);
  1692. if (b) {
  1693. js_pop(J, 2);
  1694. pc = pcstart + offset;
  1695. } else {
  1696. js_pop(J, 1);
  1697. }
  1698. break;
  1699. /* Binary bitwise operators */
  1700. case OP_BITAND:
  1701. ix = js_toint32(J, -2);
  1702. iy = js_toint32(J, -1);
  1703. js_pop(J, 2);
  1704. js_pushnumber(J, ix & iy);
  1705. break;
  1706. case OP_BITXOR:
  1707. ix = js_toint32(J, -2);
  1708. iy = js_toint32(J, -1);
  1709. js_pop(J, 2);
  1710. js_pushnumber(J, ix ^ iy);
  1711. break;
  1712. case OP_BITOR:
  1713. ix = js_toint32(J, -2);
  1714. iy = js_toint32(J, -1);
  1715. js_pop(J, 2);
  1716. js_pushnumber(J, ix | iy);
  1717. break;
  1718. /* Try and Catch */
  1719. case OP_THROW:
  1720. js_throw(J);
  1721. case OP_TRY:
  1722. offset = *pc++;
  1723. if (js_trypc(J, pc)) {
  1724. pc = J->trybuf[J->trytop].pc;
  1725. } else {
  1726. pc = pcstart + offset;
  1727. }
  1728. break;
  1729. case OP_ENDTRY:
  1730. js_endtry(J);
  1731. break;
  1732. case OP_CATCH:
  1733. READSTRING();
  1734. obj = jsV_newobject(J, JS_COBJECT, NULL);
  1735. js_pushobject(J, obj);
  1736. js_rot2(J);
  1737. js_setproperty(J, -2, str);
  1738. J->E = jsR_newenvironment(J, obj, J->E);
  1739. js_pop(J, 1);
  1740. break;
  1741. case OP_ENDCATCH:
  1742. J->E = J->E->outer;
  1743. break;
  1744. /* With */
  1745. case OP_WITH:
  1746. obj = js_toobject(J, -1);
  1747. J->E = jsR_newenvironment(J, obj, J->E);
  1748. js_pop(J, 1);
  1749. break;
  1750. case OP_ENDWITH:
  1751. J->E = J->E->outer;
  1752. break;
  1753. /* Branching */
  1754. case OP_DEBUGGER:
  1755. js_trap(J, (int)(pc - pcstart) - 1);
  1756. break;
  1757. case OP_JUMP:
  1758. pc = pcstart + *pc;
  1759. break;
  1760. case OP_JTRUE:
  1761. offset = *pc++;
  1762. b = js_toboolean(J, -1);
  1763. js_pop(J, 1);
  1764. if (b)
  1765. pc = pcstart + offset;
  1766. break;
  1767. case OP_JFALSE:
  1768. offset = *pc++;
  1769. b = js_toboolean(J, -1);
  1770. js_pop(J, 1);
  1771. if (!b)
  1772. pc = pcstart + offset;
  1773. break;
  1774. case OP_RETURN:
  1775. J->strict = savestrict;
  1776. return;
  1777. }
  1778. }
  1779. }