Advertisement
Guest User

Untitled

a guest
Aug 20th, 2019
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 32.04 KB | None | 0 0
  1. # HG changeset patch
  2. # User Dmitry Volyntsev <xeioex@nginx.com>
  3. # Date 1565288475 -10800
  4. # Thu Aug 08 21:21:15 2019 +0300
  5. # Node ID 2ba2acdef6527f3b07e0987265841c7752d3286c
  6. # Parent 239f3511397bfbcd89de5b7433daaeaa732b1adc
  7. Fixed njs_vmcode_property_init().
  8.  
  9. Function assumed obj->__proto__ is never NULL, whereas it can became
  10. NULL after __proto__: null assignment.
  11.  
  12. diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c
  13. --- a/src/njs_vmcode.c
  14. +++ b/src/njs_vmcode.c
  15. @@ -1136,18 +1136,21 @@ njs_vmcode_property_init(njs_vm_t *vm, n
  16.  
  17. obj = njs_object(value);
  18.  
  19. - ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
  20. - if (ret == NJS_OK) {
  21. - prop = lhq.value;
  22. + if (obj->__proto__ != NULL) {
  23. + /* obj->__proto__ can be NULL after __proto__: null */
  24. + ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
  25. + if (ret == NJS_OK) {
  26. + prop = lhq.value;
  27.  
  28. - if (prop->type == NJS_PROPERTY_HANDLER) {
  29. - ret = prop->value.data.u.prop_handler(vm, value, init,
  30. - &vm->retval);
  31. - if (njs_slow_path(ret != NJS_OK)) {
  32. - return ret;
  33. + if (prop->type == NJS_PROPERTY_HANDLER) {
  34. + ret = prop->value.data.u.prop_handler(vm, value, init,
  35. + &vm->retval);
  36. + if (njs_slow_path(ret != NJS_OK)) {
  37. + return ret;
  38. + }
  39. +
  40. + break;
  41. }
  42. -
  43. - break;
  44. }
  45. }
  46.  
  47. diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
  48. --- a/src/test/njs_unit_test.c
  49. +++ b/src/test/njs_unit_test.c
  50. @@ -8776,6 +8776,12 @@ static njs_unit_test_t njs_test[] =
  51. { njs_str("({}).__proto__ = null"),
  52. njs_str("null") },
  53.  
  54. + { njs_str("({__proto__:null}).__proto__"),
  55. + njs_str("undefined") },
  56. +
  57. + { njs_str("({__proto__:null, a:1}).a"),
  58. + njs_str("1") },
  59. +
  60. { njs_str("({__proto__: []}) instanceof Array"),
  61. njs_str("true") },
  62.  
  63. # HG changeset patch
  64. # User hongzhidao <hongzhidao@gmail.com>
  65. # Date 1565250738 14400
  66. # Thu Aug 08 03:52:18 2019 -0400
  67. # Node ID 97e6b099ec1aa3a400afd023b4791c2d788583ea
  68. # Parent 2ba2acdef6527f3b07e0987265841c7752d3286c
  69. Added getter/setter literal support.
  70.  
  71. diff --git a/src/njs_disassembler.c b/src/njs_disassembler.c
  72. --- a/src/njs_disassembler.c
  73. +++ b/src/njs_disassembler.c
  74. @@ -36,15 +36,15 @@ static njs_code_name_t code_names[] = {
  75. njs_str("OBJECT COPY ") },
  76.  
  77. { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t),
  78. - njs_str("PROPERTY GET ") },
  79. + njs_str("PROP GET ") },
  80. { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
  81. - njs_str("PROPERTY INIT ") },
  82. + njs_str("PROP INIT ") },
  83. { NJS_VMCODE_PROPERTY_SET, sizeof(njs_vmcode_prop_set_t),
  84. - njs_str("PROPERTY SET ") },
  85. + njs_str("PROP SET ") },
  86. { NJS_VMCODE_PROPERTY_IN, sizeof(njs_vmcode_3addr_t),
  87. - njs_str("PROPERTY IN ") },
  88. + njs_str("PROP IN ") },
  89. { NJS_VMCODE_PROPERTY_DELETE, sizeof(njs_vmcode_3addr_t),
  90. - njs_str("PROPERTY DELETE ") },
  91. + njs_str("PROP DELETE ") },
  92. { NJS_VMCODE_INSTANCE_OF, sizeof(njs_vmcode_instance_of_t),
  93. njs_str("INSTANCE OF ") },
  94.  
  95. @@ -178,6 +178,7 @@ njs_disassemble(u_char *start, u_char *e
  96. njs_vmcode_equal_jump_t *equal;
  97. njs_vmcode_prop_foreach_t *prop_foreach;
  98. njs_vmcode_method_frame_t *method;
  99. + njs_vmcode_prop_accessor_t *prop_accessor;
  100. njs_vmcode_try_trampoline_t *try_tramp;
  101. njs_vmcode_function_frame_t *function;
  102.  
  103. @@ -305,7 +306,7 @@ njs_disassemble(u_char *start, u_char *e
  104. if (operation == NJS_VMCODE_PROPERTY_FOREACH) {
  105. prop_foreach = (njs_vmcode_prop_foreach_t *) p;
  106.  
  107. - njs_printf("%05uz PROPERTY FOREACH %04Xz %04Xz +%uz\n",
  108. + njs_printf("%05uz PROP FOREACH %04Xz %04Xz +%uz\n",
  109. p - start, (size_t) prop_foreach->next,
  110. (size_t) prop_foreach->object,
  111. (size_t) prop_foreach->offset);
  112. @@ -317,7 +318,7 @@ njs_disassemble(u_char *start, u_char *e
  113. if (operation == NJS_VMCODE_PROPERTY_NEXT) {
  114. prop_next = (njs_vmcode_prop_next_t *) p;
  115.  
  116. - njs_printf("%05uz PROPERTY NEXT %04Xz %04Xz %04Xz %uz\n",
  117. + njs_printf("%05uz PROP NEXT %04Xz %04Xz %04Xz %uz\n",
  118. p - start, (size_t) prop_next->retval,
  119. (size_t) prop_next->object, (size_t) prop_next->next,
  120. (size_t) prop_next->offset);
  121. @@ -327,6 +328,22 @@ njs_disassemble(u_char *start, u_char *e
  122. continue;
  123. }
  124.  
  125. + if (operation == NJS_VMCODE_PROPERTY_ACCESSOR) {
  126. + prop_accessor = (njs_vmcode_prop_accessor_t *) p;
  127. +
  128. + njs_printf("%05uz PROP %s ACCESSOR %04Xz %04Xz %04Xz\n",
  129. + p - start,
  130. + (prop_accessor->type == NJS_OBJECT_PROP_GETTER)
  131. + ? "GET" : "SET",
  132. + (size_t) prop_accessor->value,
  133. + (size_t) prop_accessor->object,
  134. + (size_t) prop_accessor->property);
  135. +
  136. + p += sizeof(njs_vmcode_prop_accessor_t);
  137. +
  138. + continue;
  139. + }
  140. +
  141. if (operation == NJS_VMCODE_TRY_START) {
  142. try_start = (njs_vmcode_try_start_t *) p;
  143.  
  144. diff --git a/src/njs_generator.c b/src/njs_generator.c
  145. --- a/src/njs_generator.c
  146. +++ b/src/njs_generator.c
  147. @@ -119,6 +119,8 @@ static njs_int_t njs_generate_operation_
  148. njs_generator_t *generator, njs_parser_node_t *node);
  149. static njs_int_t njs_generate_object(njs_vm_t *vm, njs_generator_t *generator,
  150. njs_parser_node_t *node);
  151. +static njs_int_t njs_generate_property_accessor(njs_vm_t *vm,
  152. + njs_generator_t *generator, njs_parser_node_t *node);
  153. static njs_int_t njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
  154. njs_parser_node_t *node);
  155. static njs_int_t njs_generate_function(njs_vm_t *vm, njs_generator_t *generator,
  156. @@ -398,6 +400,10 @@ njs_generator(njs_vm_t *vm, njs_generato
  157. case NJS_TOKEN_OBJECT:
  158. return njs_generate_object(vm, generator, node);
  159.  
  160. + case NJS_TOKEN_PROPERTY_GETTER:
  161. + case NJS_TOKEN_PROPERTY_SETTER:
  162. + return njs_generate_property_accessor(vm, generator, node);
  163. +
  164. case NJS_TOKEN_ARRAY:
  165. return njs_generate_array(vm, generator, node);
  166.  
  167. @@ -1896,6 +1902,49 @@ njs_generate_object(njs_vm_t *vm, njs_ge
  168.  
  169.  
  170. static njs_int_t
  171. +njs_generate_property_accessor(njs_vm_t *vm, njs_generator_t *generator,
  172. + njs_parser_node_t *node)
  173. +{
  174. + njs_int_t ret;
  175. + njs_parser_node_t *lvalue, *function, *object, *property;
  176. + njs_vmcode_prop_accessor_t *accessor;
  177. +
  178. + lvalue = node->left;
  179. + function = node->right;
  180. +
  181. + object = lvalue->left;
  182. +
  183. + ret = njs_generator(vm, generator, object);
  184. + if (njs_slow_path(ret != NJS_OK)) {
  185. + return ret;
  186. + }
  187. +
  188. + property = lvalue->right;
  189. +
  190. + ret = njs_generator(vm, generator, property);
  191. + if (njs_slow_path(ret != NJS_OK)) {
  192. + return ret;
  193. + }
  194. +
  195. + ret = njs_generator(vm, generator, function);
  196. + if (njs_slow_path(ret != NJS_OK)) {
  197. + return ret;
  198. + }
  199. +
  200. + njs_generate_code(generator, njs_vmcode_prop_accessor_t, accessor,
  201. + NJS_VMCODE_PROPERTY_ACCESSOR, 3);
  202. +
  203. + accessor->value = function->index;
  204. + accessor->object = object->index;
  205. + accessor->property = property->index;
  206. + accessor->type = (node->token == NJS_TOKEN_PROPERTY_GETTER)
  207. + ? NJS_OBJECT_PROP_GETTER : NJS_OBJECT_PROP_SETTER;
  208. +
  209. + return NJS_OK;
  210. +}
  211. +
  212. +
  213. +static njs_int_t
  214. njs_generate_array(njs_vm_t *vm, njs_generator_t *generator,
  215. njs_parser_node_t *node)
  216. {
  217. diff --git a/src/njs_lexer.h b/src/njs_lexer.h
  218. --- a/src/njs_lexer.h
  219. +++ b/src/njs_lexer.h
  220. @@ -125,6 +125,8 @@ typedef enum {
  221. NJS_TOKEN_PROPERTY,
  222. NJS_TOKEN_PROPERTY_INIT,
  223. NJS_TOKEN_PROPERTY_DELETE,
  224. + NJS_TOKEN_PROPERTY_GETTER,
  225. + NJS_TOKEN_PROPERTY_SETTER,
  226.  
  227. NJS_TOKEN_ARRAY,
  228.  
  229. diff --git a/src/njs_lexer_keyword.c b/src/njs_lexer_keyword.c
  230. --- a/src/njs_lexer_keyword.c
  231. +++ b/src/njs_lexer_keyword.c
  232. @@ -186,6 +186,8 @@ njs_lexer_keyword(njs_lexer_t *lexer, nj
  233. lhq.key = lt->text;
  234. lhq.proto = &njs_keyword_hash_proto;
  235.  
  236. + lexer->keyword = 0;
  237. +
  238. if (njs_lvlhsh_find(&lexer->keywords_hash, &lhq) == NJS_OK) {
  239. keyword = lhq.value;
  240. lt->token = keyword->token;
  241. diff --git a/src/njs_object.c b/src/njs_object.c
  242. --- a/src/njs_object.c
  243. +++ b/src/njs_object.c
  244. @@ -1112,7 +1112,8 @@ njs_object_define_property(njs_vm_t *vm,
  245.  
  246. name = njs_arg(args, nargs, 2);
  247.  
  248. - ret = njs_object_prop_define(vm, value, name, desc);
  249. + ret = njs_object_prop_define(vm, value, name,
  250. + NJS_OBJECT_PROP_DESCRIPTOR, desc);
  251. if (njs_slow_path(ret != NJS_OK)) {
  252. return NJS_ERROR;
  253. }
  254. @@ -1165,7 +1166,9 @@ njs_object_define_properties(njs_vm_t *v
  255. }
  256.  
  257. if (prop->enumerable && njs_is_object(&prop->value)) {
  258. - ret = njs_object_prop_define(vm, value, &prop->name, &prop->value);
  259. + ret = njs_object_prop_define(vm, value, &prop->name,
  260. + NJS_OBJECT_PROP_DESCRIPTOR,
  261. + &prop->value);
  262.  
  263. if (njs_slow_path(ret != NJS_OK)) {
  264. return NJS_ERROR;
  265. diff --git a/src/njs_object.h b/src/njs_object.h
  266. --- a/src/njs_object.h
  267. +++ b/src/njs_object.h
  268. @@ -8,6 +8,11 @@
  269. #define _NJS_OBJECT_H_INCLUDED_
  270.  
  271.  
  272. +#define NJS_OBJECT_PROP_DESCRIPTOR 0
  273. +#define NJS_OBJECT_PROP_GETTER 1
  274. +#define NJS_OBJECT_PROP_SETTER 2
  275. +
  276. +
  277. #define njs_is_data_descriptor(prop) \
  278. ((prop)->writable != NJS_ATTRIBUTE_UNSET || njs_is_valid(&(prop)->value))
  279.  
  280. @@ -68,7 +73,7 @@ njs_object_prop_t *njs_object_prop_alloc
  281. njs_int_t njs_object_property(njs_vm_t *vm, const njs_value_t *value,
  282. njs_lvlhsh_query_t *lhq, njs_value_t *retval);
  283. njs_int_t njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
  284. - njs_value_t *name, njs_value_t *value);
  285. + njs_value_t *name, uint8_t type, njs_value_t *value);
  286. njs_int_t njs_object_prop_descriptor(njs_vm_t *vm, njs_value_t *dest,
  287. njs_value_t *value, njs_value_t *setval);
  288. const char *njs_prop_type_string(njs_object_prop_type_t type);
  289. diff --git a/src/njs_object_prop.c b/src/njs_object_prop.c
  290. --- a/src/njs_object_prop.c
  291. +++ b/src/njs_object_prop.c
  292. @@ -8,8 +8,8 @@
  293. #include <njs_main.h>
  294.  
  295.  
  296. -static njs_object_prop_t *njs_descriptor_prop(njs_vm_t *vm,
  297. - const njs_value_t *name, const njs_value_t *desc);
  298. +static njs_int_t njs_descriptor_prop(njs_vm_t *vm,
  299. + njs_object_prop_t *prop, const njs_value_t *desc);
  300.  
  301.  
  302. njs_object_prop_t *
  303. @@ -102,7 +102,7 @@ found:
  304. */
  305. njs_int_t
  306. njs_object_prop_define(njs_vm_t *vm, njs_value_t *object,
  307. - njs_value_t *name, njs_value_t *value)
  308. + njs_value_t *name, uint8_t type, njs_value_t *value)
  309. {
  310. njs_int_t ret;
  311. njs_object_prop_t *prop, *prev;
  312. @@ -116,11 +116,38 @@ njs_object_prop_define(njs_vm_t *vm, njs
  313. return ret;
  314. }
  315.  
  316. - prop = njs_descriptor_prop(vm, name, value);
  317. + prop = njs_object_prop_alloc(vm, name, &njs_value_invalid,
  318. + NJS_ATTRIBUTE_UNSET);
  319. if (njs_slow_path(prop == NULL)) {
  320. return NJS_ERROR;
  321. }
  322.  
  323. + switch (type) {
  324. +
  325. + case NJS_OBJECT_PROP_DESCRIPTOR:
  326. + if (njs_descriptor_prop(vm, prop, value) != NJS_OK) {
  327. + return NJS_ERROR;
  328. + }
  329. +
  330. + break;
  331. +
  332. + case NJS_OBJECT_PROP_GETTER:
  333. + prop->getter = *value;
  334. + prop->setter = njs_value_invalid;
  335. + prop->enumerable = NJS_ATTRIBUTE_TRUE;
  336. + prop->configurable = NJS_ATTRIBUTE_TRUE;
  337. +
  338. + break;
  339. +
  340. + case NJS_OBJECT_PROP_SETTER:
  341. + prop->setter = *value;
  342. + prop->getter = njs_value_invalid;
  343. + prop->enumerable = NJS_ATTRIBUTE_TRUE;
  344. + prop->configurable = NJS_ATTRIBUTE_TRUE;
  345. +
  346. + break;
  347. + }
  348. +
  349. if (njs_fast_path(ret == NJS_DECLINED)) {
  350.  
  351. /* 6.2.5.6 CompletePropertypropriptor */
  352. @@ -332,37 +359,30 @@ exception:
  353. }
  354.  
  355.  
  356. -static njs_object_prop_t *
  357. -njs_descriptor_prop(njs_vm_t *vm, const njs_value_t *name,
  358. +static njs_int_t
  359. +njs_descriptor_prop(njs_vm_t *vm, njs_object_prop_t *prop,
  360. const njs_value_t *desc)
  361. {
  362. njs_int_t ret;
  363. njs_bool_t data, accessor;
  364. njs_value_t value;
  365. - njs_object_prop_t *prop;
  366. njs_lvlhsh_query_t lhq;
  367.  
  368. data = 0;
  369. accessor = 0;
  370.  
  371. - prop = njs_object_prop_alloc(vm, name, &njs_value_invalid,
  372. - NJS_ATTRIBUTE_UNSET);
  373. - if (njs_slow_path(prop == NULL)) {
  374. - return NULL;
  375. - }
  376. -
  377. njs_object_property_init(&lhq, "get", NJS_GET_HASH);
  378.  
  379. ret = njs_object_property(vm, desc, &lhq, &value);
  380.  
  381. if (njs_slow_path(ret == NJS_ERROR)) {
  382. - return NULL;
  383. + return NJS_ERROR;
  384. }
  385.  
  386. if (ret == NJS_OK) {
  387. if (njs_is_defined(&value) && !njs_is_function(&value)) {
  388. njs_type_error(vm, "Getter must be a function");
  389. - return NULL;
  390. + return NJS_ERROR;
  391. }
  392.  
  393. accessor = 1;
  394. @@ -379,13 +399,13 @@ njs_descriptor_prop(njs_vm_t *vm, const
  395. ret = njs_object_property(vm, desc, &lhq, &value);
  396.  
  397. if (njs_slow_path(ret == NJS_ERROR)) {
  398. - return NULL;
  399. + return ret;
  400. }
  401.  
  402. if (ret == NJS_OK) {
  403. if (njs_is_defined(&value) && !njs_is_function(&value)) {
  404. njs_type_error(vm, "Setter must be a function");
  405. - return NULL;
  406. + return NJS_ERROR;
  407. }
  408.  
  409. accessor = 1;
  410. @@ -402,7 +422,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
  411. ret = njs_object_property(vm, desc, &lhq, &value);
  412.  
  413. if (njs_slow_path(ret == NJS_ERROR)) {
  414. - return NULL;
  415. + return ret;
  416. }
  417.  
  418. if (ret == NJS_OK) {
  419. @@ -416,7 +436,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
  420. ret = njs_object_property(vm, desc, &lhq, &value);
  421.  
  422. if (njs_slow_path(ret == NJS_ERROR)) {
  423. - return NULL;
  424. + return ret;
  425. }
  426.  
  427. if (ret == NJS_OK) {
  428. @@ -430,7 +450,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
  429. ret = njs_object_property(vm, desc, &lhq, &value);
  430.  
  431. if (njs_slow_path(ret == NJS_ERROR)) {
  432. - return NULL;
  433. + return ret;
  434. }
  435.  
  436. if (ret == NJS_OK) {
  437. @@ -443,7 +463,7 @@ njs_descriptor_prop(njs_vm_t *vm, const
  438. ret = njs_object_property(vm, desc, &lhq, &value);
  439.  
  440. if (njs_slow_path(ret == NJS_ERROR)) {
  441. - return NULL;
  442. + return ret;
  443. }
  444.  
  445. if (ret == NJS_OK) {
  446. @@ -453,10 +473,10 @@ njs_descriptor_prop(njs_vm_t *vm, const
  447. if (accessor && data) {
  448. njs_type_error(vm, "Cannot both specify accessors "
  449. "and a value or writable attribute");
  450. - return NULL;
  451. + return NJS_ERROR;
  452. }
  453.  
  454. - return prop;
  455. + return NJS_OK;
  456. }
  457.  
  458.  
  459. diff --git a/src/njs_parser_terminal.c b/src/njs_parser_terminal.c
  460. --- a/src/njs_parser_terminal.c
  461. +++ b/src/njs_parser_terminal.c
  462. @@ -19,6 +19,10 @@ static njs_token_t njs_parser_object(njs
  463. static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
  464. njs_parser_node_t *parent, njs_parser_node_t *property,
  465. njs_parser_node_t *value);
  466. +static njs_int_t njs_parser_property_accessor(njs_vm_t *vm,
  467. + njs_parser_t *parser, njs_parser_node_t *parent,
  468. + njs_parser_node_t *property, njs_parser_node_t *value,
  469. + njs_token_t accessor);
  470. static njs_token_t njs_parser_array(njs_vm_t *vm, njs_parser_t *parser,
  471. njs_parser_node_t *array);
  472. static njs_int_t njs_parser_array_item(njs_vm_t *vm, njs_parser_t *parser,
  473. @@ -482,16 +486,17 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  474. uint32_t hash, token_line;
  475. njs_int_t ret;
  476. njs_str_t name;
  477. - njs_token_t token, prop_token;
  478. + njs_token_t token, accessor;
  479. njs_lexer_t *lexer;
  480. njs_parser_node_t *object, *property, *expression;
  481. njs_function_lambda_t *lambda;
  482.  
  483. lexer = parser->lexer;
  484.  
  485. - /* GCC and Clang complain about uninitialized hash. */
  486. + /* GCC and Clang complain about uninitialized values. */
  487. hash = 0;
  488. token_line = 0;
  489. + property = NULL;
  490.  
  491. object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
  492. if (njs_slow_path(object == NULL)) {
  493. @@ -501,16 +506,46 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  494. object->u.object = obj;
  495.  
  496. for ( ;; ) {
  497. - prop_token = njs_parser_token(vm, parser);
  498. - if (njs_slow_path(prop_token <= NJS_TOKEN_ILLEGAL)) {
  499. - return prop_token;
  500. + token = njs_parser_token(vm, parser);
  501. + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  502. + return token;
  503. }
  504.  
  505. + accessor = 0;
  506. njs_memzero(&name, sizeof(njs_str_t));
  507.  
  508. - switch (prop_token) {
  509. + if (token == NJS_TOKEN_NAME || lexer->keyword) {
  510. + name = *njs_parser_text(parser);
  511. + hash = njs_parser_key_hash(parser);
  512. + token_line = njs_parser_token_line(parser);
  513. +
  514. + property = njs_parser_node_string(vm, parser);
  515. + if (njs_slow_path(property == NULL)) {
  516. + return NJS_TOKEN_ERROR;
  517. + }
  518. +
  519. + if (token == NJS_TOKEN_NAME && name.length == 3
  520. + && (memcmp(name.start, "get", 3) == 0
  521. + || memcmp(name.start, "set", 3) == 0))
  522. + {
  523. + accessor = (name.start[0] == 'g') ? NJS_TOKEN_PROPERTY_GETTER
  524. + : NJS_TOKEN_PROPERTY_SETTER;
  525. +
  526. + token = njs_parser_token(vm, parser);
  527. + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  528. + return token;
  529. + }
  530. + }
  531. + }
  532. +
  533. + switch (token) {
  534.  
  535. case NJS_TOKEN_CLOSE_BRACE:
  536. + if (accessor) {
  537. + accessor = 0;
  538. + break;
  539. + }
  540. +
  541. goto done;
  542.  
  543. case NJS_TOKEN_OPEN_BRACKET:
  544. @@ -530,13 +565,14 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  545.  
  546. property = parser->node;
  547.  
  548. - token = njs_parser_match(vm, parser, token, NJS_TOKEN_CLOSE_BRACKET);
  549. + token = njs_parser_match(vm, parser, token,
  550. + NJS_TOKEN_CLOSE_BRACKET);
  551. break;
  552.  
  553. case NJS_TOKEN_NUMBER:
  554. case NJS_TOKEN_STRING:
  555. case NJS_TOKEN_ESCAPE_STRING:
  556. - token = njs_parser_terminal(vm, parser, prop_token);
  557. + token = njs_parser_terminal(vm, parser, token);
  558. if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  559. return token;
  560. }
  561. @@ -545,58 +581,27 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  562. break;
  563.  
  564. default:
  565. - if (prop_token != NJS_TOKEN_NAME && !lexer->keyword) {
  566. - return NJS_TOKEN_ILLEGAL;
  567. + if (token != NJS_TOKEN_NAME && !lexer->keyword) {
  568. + if (name.length == 0) {
  569. + return NJS_TOKEN_ILLEGAL;
  570. + }
  571. +
  572. + accessor = 0;
  573. + break;
  574. }
  575.  
  576. - property = njs_parser_node_string(vm, parser);
  577. - if (njs_slow_path(property == NULL)) {
  578. - return NJS_TOKEN_ERROR;
  579. + if (accessor) {
  580. + property = njs_parser_node_string(vm, parser);
  581. + if (njs_slow_path(property == NULL)) {
  582. + return NJS_TOKEN_ERROR;
  583. + }
  584. }
  585.  
  586. - name = *njs_parser_text(parser);
  587. - hash = njs_parser_key_hash(parser);
  588. - token_line = njs_parser_token_line(parser);
  589. -
  590. token = njs_parser_token(vm, parser);
  591. break;
  592. }
  593.  
  594. - switch (token) {
  595. -
  596. - case NJS_TOKEN_COMMA:
  597. - case NJS_TOKEN_CLOSE_BRACE:
  598. -
  599. - if (name.length == 0
  600. - || prop_token == NJS_TOKEN_THIS
  601. - || prop_token == NJS_TOKEN_GLOBAL_THIS)
  602. - {
  603. - return NJS_TOKEN_ILLEGAL;
  604. - }
  605. -
  606. - expression = njs_parser_reference(vm, parser, prop_token, &name,
  607. - hash, token_line);
  608. - if (njs_slow_path(expression == NULL)) {
  609. - return NJS_TOKEN_ERROR;
  610. - }
  611. -
  612. - break;
  613. -
  614. - case NJS_TOKEN_COLON:
  615. - token = njs_parser_token(vm, parser);
  616. - if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  617. - return token;
  618. - }
  619. -
  620. - token = njs_parser_assignment_expression(vm, parser, token);
  621. - if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  622. - return token;
  623. - }
  624. -
  625. - expression = parser->node;
  626. - break;
  627. -
  628. - case NJS_TOKEN_OPEN_PARENTHESIS:
  629. + if (accessor) {
  630. expression = njs_parser_node_new(vm, parser,
  631. NJS_TOKEN_FUNCTION_EXPRESSION);
  632. if (njs_slow_path(expression == NULL)) {
  633. @@ -606,7 +611,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  634. expression->token_line = njs_parser_token_line(parser);
  635. parser->node = expression;
  636.  
  637. - lambda = njs_function_lambda_alloc(vm, 0);
  638. + lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
  639. if (njs_slow_path(lambda == NULL)) {
  640. return NJS_TOKEN_ERROR;
  641. }
  642. @@ -618,15 +623,95 @@ njs_parser_object(njs_vm_t *vm, njs_pars
  643. return token;
  644. }
  645.  
  646. - break;
  647. + if (accessor == NJS_TOKEN_PROPERTY_GETTER) {
  648. + if (lambda->nargs != 0) {
  649. + njs_parser_syntax_error(vm, parser,
  650. + "Getter must not have any formal parameters");
  651. + return NJS_TOKEN_ILLEGAL;
  652. + }
  653.  
  654. - default:
  655. - return NJS_TOKEN_ILLEGAL;
  656. - }
  657. + } else {
  658. + if (lambda->nargs != 1) {
  659. + njs_parser_syntax_error(vm, parser,
  660. + "Setter must have exactly one formal parameter");
  661. + return NJS_TOKEN_ILLEGAL;
  662. + }
  663. + }
  664.  
  665. - ret = njs_parser_object_property(vm, parser, obj, property, expression);
  666. - if (njs_slow_path(ret != NJS_OK)) {
  667. - return NJS_TOKEN_ERROR;
  668. + ret = njs_parser_property_accessor(vm, parser, obj, property,
  669. + expression, accessor);
  670. + if (njs_slow_path(ret != NJS_OK)) {
  671. + return NJS_TOKEN_ERROR;
  672. + }
  673. +
  674. + } else {
  675. + switch (token) {
  676. +
  677. + case NJS_TOKEN_COMMA:
  678. + case NJS_TOKEN_CLOSE_BRACE:
  679. +
  680. + if (name.length == 0
  681. + || lexer->prev_token == NJS_TOKEN_THIS
  682. + || lexer->prev_token == NJS_TOKEN_GLOBAL_THIS)
  683. + {
  684. + return NJS_TOKEN_ILLEGAL;
  685. + }
  686. +
  687. + expression = njs_parser_reference(vm, parser, lexer->prev_token,
  688. + &name, hash, token_line);
  689. + if (njs_slow_path(expression == NULL)) {
  690. + return NJS_TOKEN_ERROR;
  691. + }
  692. +
  693. + break;
  694. +
  695. + case NJS_TOKEN_COLON:
  696. + token = njs_parser_token(vm, parser);
  697. + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  698. + return token;
  699. + }
  700. +
  701. + token = njs_parser_assignment_expression(vm, parser, token);
  702. + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  703. + return token;
  704. + }
  705. +
  706. + expression = parser->node;
  707. + break;
  708. +
  709. + case NJS_TOKEN_OPEN_PARENTHESIS:
  710. + expression = njs_parser_node_new(vm, parser,
  711. + NJS_TOKEN_FUNCTION_EXPRESSION);
  712. + if (njs_slow_path(expression == NULL)) {
  713. + return NJS_TOKEN_ERROR;
  714. + }
  715. +
  716. + expression->token_line = njs_parser_token_line(parser);
  717. + parser->node = expression;
  718. +
  719. + lambda = njs_function_lambda_alloc(vm, 0);
  720. + if (njs_slow_path(lambda == NULL)) {
  721. + return NJS_TOKEN_ERROR;
  722. + }
  723. +
  724. + expression->u.value.data.u.lambda = lambda;
  725. +
  726. + token = njs_parser_function_lambda(vm, parser, lambda, token);
  727. + if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
  728. + return token;
  729. + }
  730. +
  731. + break;
  732. +
  733. + default:
  734. + return NJS_TOKEN_ILLEGAL;
  735. + }
  736. +
  737. + ret = njs_parser_object_property(vm, parser, obj, property,
  738. + expression);
  739. + if (njs_slow_path(ret != NJS_OK)) {
  740. + return NJS_TOKEN_ERROR;
  741. + }
  742. }
  743.  
  744. if (token == NJS_TOKEN_CLOSE_BRACE) {
  745. @@ -690,6 +775,49 @@ njs_parser_object_property(njs_vm_t *vm,
  746. }
  747.  
  748.  
  749. +static njs_int_t
  750. +njs_parser_property_accessor(njs_vm_t *vm, njs_parser_t *parser,
  751. + njs_parser_node_t *parent, njs_parser_node_t *property,
  752. + njs_parser_node_t *value, njs_token_t accessor)
  753. +{
  754. + njs_parser_node_t *node, *stmt, *object, *propref;
  755. +
  756. + object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
  757. + if (njs_slow_path(object == NULL)) {
  758. + return NJS_TOKEN_ERROR;
  759. + }
  760. +
  761. + object->u.object = parent;
  762. +
  763. + propref = njs_parser_node_new(vm, parser, 0);
  764. + if (njs_slow_path(propref == NULL)) {
  765. + return NJS_ERROR;
  766. + }
  767. +
  768. + propref->left = object;
  769. + propref->right = property;
  770. +
  771. + node = njs_parser_node_new(vm, parser, accessor);
  772. + if (njs_slow_path(node == NULL)) {
  773. + return NJS_ERROR;
  774. + }
  775. +
  776. + node->left = propref;
  777. + node->right = value;
  778. +
  779. + stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT);
  780. + if (njs_slow_path(stmt == NULL)) {
  781. + return NJS_ERROR;
  782. + }
  783. +
  784. + stmt->right = node;
  785. + stmt->left = parent->left;
  786. + parent->left = stmt;
  787. +
  788. + return NJS_OK;
  789. +}
  790. +
  791. +
  792. static njs_token_t
  793. njs_parser_array(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *array)
  794. {
  795. diff --git a/src/njs_vmcode.c b/src/njs_vmcode.c
  796. --- a/src/njs_vmcode.c
  797. +++ b/src/njs_vmcode.c
  798. @@ -86,9 +86,10 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
  799. njs_str_t string;
  800. njs_uint_t hint;
  801. njs_bool_t valid, lambda_call;
  802. - njs_value_t *retval, *value1, *value2, *src, *s1, *s2;
  803. - njs_value_t numeric1, numeric2, primitive1, primitive2,
  804. - dst;
  805. + njs_value_t *retval, *value1, *value2;
  806. + njs_value_t *src, *s1, *s2, dst;
  807. + njs_value_t *function, name;
  808. + njs_value_t numeric1, numeric2, primitive1, primitive2;
  809. njs_frame_t *frame;
  810. njs_jump_off_t ret;
  811. njs_vmcode_this_t *this;
  812. @@ -103,6 +104,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_c
  813. njs_vmcode_equal_jump_t *equal;
  814. njs_vmcode_try_return_t *try_return;
  815. njs_vmcode_method_frame_t *method_frame;
  816. + njs_vmcode_prop_accessor_t *accessor;
  817. njs_vmcode_function_frame_t *function_frame;
  818.  
  819. next:
  820. @@ -599,6 +601,27 @@ next:
  821. ret = sizeof(njs_vmcode_prop_set_t);
  822. break;
  823.  
  824. + case NJS_VMCODE_PROPERTY_ACCESSOR:
  825. + accessor = (njs_vmcode_prop_accessor_t *) pc;
  826. + function = njs_vmcode_operand(vm, accessor->value);
  827. +
  828. + ret = njs_value_to_string(vm, &name, value2);
  829. + if (njs_slow_path(ret != NJS_OK)) {
  830. + njs_internal_error(vm, "failed conversion of type \"%s\" "
  831. + "to string while property define",
  832. + njs_type_string(value2->type));
  833. + return NJS_ERROR;
  834. + }
  835. +
  836. + ret = njs_object_prop_define(vm, value1, &name, accessor->type,
  837. + function);
  838. + if (njs_slow_path(ret != NJS_OK)) {
  839. + return NJS_ERROR;
  840. + }
  841. +
  842. + ret = sizeof(njs_vmcode_prop_accessor_t);
  843. + break;
  844. +
  845. case NJS_VMCODE_IF_TRUE_JUMP:
  846. case NJS_VMCODE_IF_FALSE_JUMP:
  847. ret = njs_is_true(value1);
  848. diff --git a/src/njs_vmcode.h b/src/njs_vmcode.h
  849. --- a/src/njs_vmcode.h
  850. +++ b/src/njs_vmcode.h
  851. @@ -40,6 +40,7 @@ typedef uint8_t
  852. #define NJS_VMCODE_STOP VMCODE0(0)
  853. #define NJS_VMCODE_JUMP VMCODE0(1)
  854. #define NJS_VMCODE_PROPERTY_SET VMCODE0(2)
  855. +#define NJS_VMCODE_PROPERTY_ACCESSOR VMCODE0(3)
  856. #define NJS_VMCODE_IF_TRUE_JUMP VMCODE0(4)
  857. #define NJS_VMCODE_IF_FALSE_JUMP VMCODE0(5)
  858. #define NJS_VMCODE_IF_EQUAL_JUMP VMCODE0(6)
  859. @@ -261,6 +262,15 @@ typedef struct {
  860.  
  861. typedef struct {
  862. njs_vmcode_t code;
  863. + njs_index_t value;
  864. + njs_index_t object;
  865. + njs_index_t property;
  866. + uint8_t type;
  867. +} njs_vmcode_prop_accessor_t;
  868. +
  869. +
  870. +typedef struct {
  871. + njs_vmcode_t code;
  872. njs_index_t next;
  873. njs_index_t object;
  874. njs_jump_off_t offset;
  875. diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c
  876. --- a/src/test/njs_unit_test.c
  877. +++ b/src/test/njs_unit_test.c
  878. @@ -10096,6 +10096,58 @@ static njs_unit_test_t njs_test[] =
  879. "JSON.stringify(Object.getOwnPropertyDescriptor(o, 'a')).set"),
  880. njs_str("undefined") },
  881.  
  882. + { njs_str("var get = 'get'; var o = { get }; o.get"),
  883. + njs_str("get") },
  884. +
  885. + { njs_str("var o = { get foo() { return 'bar'; } }; o.foo"),
  886. + njs_str("bar") },
  887. +
  888. + { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} };o.lazy"),
  889. + njs_str("8") },
  890. +
  891. + { njs_str("var o = { get lazy() { delete this.lazy; return this.lazy = Math.pow(2,3)} }; o.lazy;"
  892. + "Object.getOwnPropertyDescriptor(o, 'lazy').value"),
  893. + njs_str("8") },
  894. +
  895. + { njs_str("var o = { get get() { return 'bar'; } }; o.get"),
  896. + njs_str("bar") },
  897. +
  898. + { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; } }; o.foo"),
  899. + njs_str("bar") },
  900. +
  901. + { njs_str("var o = { get [{toString(){return 'get'}}]() { return 'bar'; } }; o.get"),
  902. + njs_str("bar") },
  903. +
  904. + { njs_str("var o = { get [{toString(){return {} }}]() { return 'bar'; } }; o.get"),
  905. + njs_str("InternalError: failed conversion of type \"object\" to string while property define") },
  906. +
  907. + { njs_str("var o = { get foo(v1, v2) { return 'bar'; } }; o.foo"),
  908. + njs_str("SyntaxError: Getter must not have any formal parameters in 1") },
  909. +
  910. + { njs_str("var o = { baz: 'bar', set foo(v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
  911. + njs_str("baz") },
  912. +
  913. + { njs_str("var o = { baz: 'bar', set set(v) { this.baz = v; } }; o.set = 'baz'; o.baz"),
  914. + njs_str("baz") },
  915. +
  916. + { njs_str("var expr = 'foo'; var o = { baz: 'bar', set [expr](v) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
  917. + njs_str("baz") },
  918. +
  919. + { njs_str("var o = { baz: 'bar', set foo(v1, v2) { this.baz = v; } }; o.foo = 'baz'; o.baz"),
  920. + njs_str("SyntaxError: Setter must have exactly one formal parameter in 1") },
  921. +
  922. + { njs_str("var o = { get foo() { return 'bar'; }, set foo(v) { this.baz = v; } }; o.foo"),
  923. + njs_str("bar") },
  924. +
  925. + { njs_str("var expr = 'foo'; var o = { get [expr]() { return 'bar'; }, set [expr](v) { this.baz = v; } }; o.foo"),
  926. + njs_str("bar") },
  927. +
  928. + { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').enumerable"),
  929. + njs_str("true") },
  930. +
  931. + { njs_str("Object.getOwnPropertyDescriptor({get foo() {}}, 'foo').configurable"),
  932. + njs_str("true") },
  933. +
  934. { njs_str("var p = { a:5 }; var o = Object.create(p);"
  935. "Object.getPrototypeOf(o) === p"),
  936. njs_str("true") },
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement